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

posted on 2011-05-06 22:43  奋斗青春  阅读(262)  评论(0编辑  收藏  举报