和poj的2513差不多,不过没那么麻烦,这个不需要用Trie树。。
并查集+欧拉回路。
先看成是一个无向图,判断连通性。 之后记录每一个字母的入度和出度。
这个也是两种情况:
一种:所有点的入度==其出度;
另一种:只有两个点的入度不等于它的出度, 并且其中一个点的入度==其出度+1,另一个点的出度==其入度+1;
这样就很简单了^_^
# include<stdio.h> # include<string.h> # define MAX 27 int father[MAX],indegree[MAX],outdegree[MAX]; int find(int x) { while(father[x]!=x) x=father[x]; return x; } void Union(int a,int b) { int x,y,min; x=find(a); y=find(b); min=x<y?x:y; father[a]=father[b]=father[x]=father[y]=min; } int main() { int ncase,i,j,n,ans1,ans2,len,count1,flag,count2; char str[1005]; scanf("%d",&ncase); while(ncase--) { for(i=0;i<MAX;i++) { father[i]=i; indegree[i]=0; outdegree[i]=0; } scanf("%d",&n); while(n--) { scanf("%s",str); len=strlen(str); ans1=str[0]-'a'; ans2=str[len-1]-'a'; outdegree[ans1]++; indegree[ans2]++; Union(ans1,ans2); } for(i=0;i<26;i++) if(indegree[i]!=0 || outdegree[i]!=0) break;//找到出现的字母中最小的一个 flag=0; count1=0;// count2=0; for(j=i;j<26;j++) { if(outdegree[j]==0 && indegree[j]==0) continue;///不考虑未出现的字母 if(find(j)!=i) {flag=1;break;}//判断是否连通 if(indegree[j]!=outdegree[j]) { if(outdegree[j]==indegree[j]+1) count1++;//出度比入度大的点 else if(indegree[j]==outdegree[j]+1) count2++;//入度比出度大的点 else {flag=1;break;}//如果入度、出度相差不只是1,则不能打开门 } if(count1>=2 || count2>=2) {flag=1;break;} } if(flag==1) printf("The door cannot be opened.\n"); else printf("Ordering is possible.\n"); } return 0; }