#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int M =30;
int in[M],out[M],vis[M],fa[M];
void Init()
{
for(int i=0;i<26;i++)
{
fa[i]=i;
}
}
int find(int x)
{
if(x!=fa[x])
{
fa[x]=find(fa[x]);
}
return fa[x];
}
void Union(int x,int y)
{
int a=find(x);
int b=find(y);
if(a!=b)
{
fa[a]=b;
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
Init();
int flag=1;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(vis,0,sizeof(vis));
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
char s[1100];
scanf("%s",s);
int len=strlen(s);
// (a,b) (b,c)
//将单词首尾用一条有向边相连, 这样当两个单词能相连 a->c就能连通
out[s[0]-'a']++;
in[s[len-1]-'a']++;
Union(s[0]-'a',s[len-1]-'a');//合并两个点所在的连通分量
vis[s[0]-'a']=1;
vis[s[len-1]-'a']=1;//顶点存在
}
int father;//祖先
for(int i=0;i<26;i++)
{
if(vis[i])
{
father=find(i);
break;
}
}
for(int i=0;i<26;i++)
{
if(vis[i])
{
//printf("%c",i+97);
//cout<<":"<<out[i]<<" "<<in[i]<<endl;
if(find(i)!=father)// 图不连通
{
flag=0;
break;
}
}
}
if(!flag)//不连通
{
cout<<"The door cannot be opened."<<endl;
}
else
{
int s=0,e=0;//起点和终点
for(int i=0;i<26;i++)
{
if(vis[i])
{
int tmp=in[i]-out[i];
if(tmp==1) e++;
if(tmp==-1) s++;//欧拉图:有向图 除了起点和终点度数可以相差一 其余顶点入度和出度都相同
if(e>1||s>1||tmp>1||tmp<-1)
{
flag=0;
break;
}
}
}
if(!flag)//入度!=出度
{
cout<<"The door cannot be opened."<<endl;
}
else
{
cout<<"Ordering is possible."<<endl;
}
}
}
return 0;
}
poj 1386 单词连接 欧拉图+并查集判连通
最新推荐文章于 2019-11-14 16:42:00 发布