和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;
}