Play on Words
Description Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us. There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word ``acm‘‘ Input The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing a single integer number Nthat indicates the number of plates (1 <= N <= 100000). Then exactly Nlines follow, Output Your program has to determine whether it is possible to arrange all the plates in a sequence such that the first letter of each word is equal to the last letter of the previous word. All the plates from the list must be used, each exactly once. The words mentioned If there exists such an ordering of plates, your program should print the sentence "Ordering is possible.". Otherwise, output the sentence "The door cannot be opened.". Sample Input 3 2 acm ibm 3 acm malform mouse 2 ok ok Sample Output The door cannot be opened. Ordering is possible. The door cannot be opened. Source |
[Submit] [Go Back] [Status]
[Discuss]
题意:
题目描述:
有些秘门带有一个有趣的词迷。考古学家必须解开词迷才能打开门。由于没有其他方法可以
打开门,因此词迷就变得很重要。
每个门上有许多磁盘。每个盘上有一个单词,这些磁盘必须重新排列使得每个单词第一个字
母跟前一个单词最后一个字母相同。例如单词"acm"可以跟在单词"motorola"的后面。你的任务是
编写一个程序,读入一组单词,然后判定是否可以经过重组使得每个单词第一个字母跟前一个单
词最后一个字母相同,这样才能打开门。
每个单词只有首尾两个字母很关键,并且每个单词可以看成连接首尾两个字母的一条有向边(由首字母指向尾字母)。这样每个测试数据中的一组单词可以构造成一个图:图中的顶点为 26 个小写字母,每个单词为图中的一条边。构造好有向图后,题目要判定是否可以经过重组使得每个单词第一个字母跟前一个单词最后一个字母相同,等效于判断图中是否存在一条路径经过每条边一次且仅一次,这就是有向欧拉通路。
#include <cstdio> #include <cstring> #include<vector> #include<iostream> using namespace std; #define MAXN 100001 #define INF 100000000 char word[MAXN]; const int sz=30; int p[sz],v[sz],in[sz],out[sz],E; int G[sz][sz]; int findx(int x){ return p[x]==x?x:p[x]=findx(p[x]); } void Union(int u,int v){ p[findx(u)]=findx(v); } bool is_connect(){ int x=0; for(int i=0;i<26;i++)if(v[i]) { x=i; for(int j=0;j<26;++j)if(G[i][j]){ Union(i,j); } } x=findx(x); for(int i=0;i<26;i++)if(v[i]){ if(x!=findx(i))return false; } return true; } void AddEdge(int from,int to){ v[from]=v[to]=1; if(from==to)return; G[from][to]=1; out[from]++; in[to]++; } void Init(){ memset(in,0,sizeof in); memset(out,0,sizeof out); memset(v,0,sizeof v); memset(G,0,sizeof G); for(int i=0;i<26;i++)p[i]=i; } int main(int argc, char const *argv[]) { int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); bool ok=true; Init(); while(n--){ scanf("%s",word); AddEdge(word[0]-'a',word[strlen(word)-1]-'a'); } int x1=0,x2=0; for(int i=0;i<26;i++)if(v[i]){ if(out[i]-in[i]>1||in[i]-out[i]>1){ ok=false;break; }else if(out[i]-in[i]==1){ x1++; if(x1>1){ ok=false;break; } }else if(out[i]+1==in[i]){ x2++; if(x2>1){ ok=false;break; } } } if(x1!=x2){ ok=false; }if(ok&&!is_connect()) ok=false; puts(ok?"Ordering is possible.":"The door cannot be opened."); } return 0; }