题意就是给你n个由小写字母构成的字符串,问你能不能将这n个字符串连接起来,B能接在A后面的条件是A的最后一个字母==B的第一个字母。
然后就是将26个小写字母看成顶点集,对于一个字符串,其首字母向尾字母连一条单向边构图,所以本题就是有向图的欧拉路问题。
代码:
#include<cstdio> #include<vector> #include<cstring> #include<algorithm> using namespace std; const int N=35; int in[N],out[N]; char s[N*100]; int used[26]; int par[26]; void init() { for(int i=0;i<26;i++) par[i]=i; } int find(int x) { if(x!=par[x]) par[x]=find(par[x]); return par[x]; } void union_(int x,int y) { x=find(x); y=find(y); if(x!=y) par[y]=x; } int main() { int T,n; for(scanf("%d",&T); T--;) { memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(used,0,sizeof(used)); init(); scanf("%d",&n); while(n--) { scanf("%s",s); int st=s[0],end=s[strlen(s)-1]; st-='a',end-='a'; union_(st,end); ++in[end]; ++out[st]; used[st]=1; used[end]=1; } int sum_root=0;//根结点的个数 for(int i=0;i<26;i++) if(used[i]&&par[i]==i) sum_root++; if(sum_root!=1) { puts("The door cannot be opened."); continue; } bool ok=1,k1=0,k2=0; for(int i=0; i<26; ++i)//一点入>出,一点出>入,其余出=入 { if(in[i]==out[i]) continue; else if(in[i]-out[i]==1&&!k1) k1=1; else if(out[i]-in[i]==1&&!k2) k2=1; else { ok=0; break; } } if(ok) puts("Ordering is possible."); else puts("The door cannot be opened."); } }