题目大意:给出一些单词,问能否摆成类似成语接龙的顺序(即前一个单词的最后一个字母要和下一个单词首字母相同)。
对于每个单词,只有首尾两字母重要,该单词可看做由首字母到尾字母的一条边,即所有单词的首尾两字母看做图中节点,每个单词可看做一条边,构造好有向图后,若要摆成题意要求的顺序,即判断是否存在欧拉回路即可。
#include <stdio.h> #include <string.h> int t,n; char word[1001];//存储每个单词 int od[30],id[30];//每个顶点的出度和入度 int bused[30],p[30];//bused表示该顶点是否存在,p是并查集中的父节点 struct edge { int u,v; }edges[100010]; void init() { int i; for(i=0;i<26;i++) p[i]=i; } int get(int x) { if(p[x]==x) return x; else return p[x]=get(p[x]); } bool con() { int u,v,i; init(); for(i=0;i<n;i++) { u=edges[i].u; v=edges[i].v; u=get(u); v=get(v); if(u!=v) p[u]=v; } int sum=0; for(i=0;i<26;i++) { if(bused[i]==0)continue; if(p[i]==i) sum++; } if(sum>1) return false; else return true; } int main() { int u,v; int i,j; scanf("%d",&t); for(i=0;i<t;i++) { memset(bused,0,sizeof(bused)); memset(od,0,sizeof(od)); memset(id,0,sizeof(id)); scanf("%d",&n); for(j=0;j<n;j++) { scanf("%s",word); u=word[0]-'a';v=word[strlen(word)-1]-'a'; od[u]++;id[v]++; bused[u]=bused[v]=1; edges[j].u=u;edges[j].v=v; } bool euler=true; int one=0; int none=0; for(j=0;j<26;j++) { if(bused[j]==0)continue; if(od[j]-id[j]>1||id[j]-od[j]>1) {euler=false;break;} if(od[j]-id[j]==1) { one++; if(one>1) {euler=false;break;} } if(id[j]-od[j]==1) { none++; if(none>1) {euler=false;break;} } } if(one!=none) euler=false; if(!con()) euler=false; if(euler) printf("Ordering is possible. "); else printf("The door cannot be opened. "); } return 0; }