题意就不说了,先说下构图吧,对于一个单词,第一个字母为i,最后一个字母为j,那么连一条有向边i->j,因为如果最后可以把单词按要求排列的话,对于一个单词i...j,i是指向j的,如果将单词看成点构图,就是求汉密尔顿路了,是NP难的
这样的话,首先判断图是否连通,然后就是要判断是否为强连通或者弱连通
由欧拉判定定理:(来自nocow)
1.一个有向图具有欧拉回路,当且仅当图是连通的,且所有点的入度等于出度
2.一个有向图是弱连通图,当且仅当图是连通的,且仅有一个点 入度-出度=1,仅有另外一点 出度-入度=1,其他点 入度等于出度 3.一个有向图具有欧拉路,当且仅当图是连通的,且有零个或两个奇度数顶点,欧拉图(欧拉回路)0个,半欧拉图(只有欧拉通路)2个 记录每个出现的点的出度和入度 用并查集判断是否连通
代码:
#include<iostream> #include<cstdio> #include<memory.h> #include<string.h> using namespace std; int in[31],out[31],use[31],fa[31]; int n; char s[1005]; int find(int x) { if(x!=fa[x]) fa[x]=find(fa[x]); return fa[x]; } int main() { int i,j,T,ii,jj; scanf("%d",&T); while(T--) { scanf("%d",&n); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(use,0,sizeof(use)); for(i=0;i<=26;i++) fa[i]=i; while(n--) { scanf("%s",&s); i=s[0]-'a'; j=s[strlen(s)-1]-'a'; use[i]=use[j]=1; in[j]++; out[i]++; ii=find(i); jj=find(j); if(ii!=jj) { fa[jj]=ii; } } int cnt1=0,cnt2=0,cnt3=0; int flag=1; /*for(i=0;i<26;i++) cout<<in[i]<<" "; cout<<endl; for(i=0;i<26;i++) cout<<out[i]<<" "; cout<<endl;*/ for(i=0;i<26;i++) { if(use[i]) { if(fa[i]==i) cnt1++; if(in[i]!=out[i]) { if(in[i]-out[i]==1) cnt2++; else if(out[i]-in[i]==1) cnt3++; else flag=0; } } } //cout<<cnt1<<" "<<cnt2<<" "<<cnt3<<"flag "<<flag<<endl; if((cnt1==1&&flag&&cnt2==0&&cnt3==0)||(cnt1==1&&flag&&cnt2==1&&cnt3==1)) puts("Ordering is possible."); else puts("The door cannot be opened."); } return 0; }