poj 1386 Play on Words

/*
题意: 有一些单词,排列这些单词,要求前一个单词的最后一个字母与后一个单词的第一个字母相同。
问能否对所有单词进行排列

思路: 把单词的第一个字母和最后一个字母作为点,由第一个字母向最后一个字母连一条有向边,
问题转化为判断一个有向图是否存在欧拉道路

有向图存在欧拉道路的条件: 在忽略边的方向后,图必须是连通的,同时最多只能有两个点的入度不等于出度,
而且必须是其中一个点的出度刚好比入度大1(把它作为起点),另一个的入度比出度大1(把它作为终点).

*/

#include <iostream> //有向图的欧拉道路
using namespace std;
int in[26],out[26],p[26],vis[26]; //vis表示有哪些字母出现
int find(int x)
{
return p[x]==x ? x : p[x]=find(p[x]);
}
void Union(int a,int b)
{
int x=find(a),y=find(b);
if(x!=y)
p[x]=y;
}
int main()
{
int cases,n,i;
char str[1010];
scanf("%d",&cases);
while(cases--)
{
for(i=0;i<26;++i)
{
in[i]=out[i]=0;
vis[i]=0;
p[i]=i;
}
scanf("%d",&n);
while(n--)
{
scanf("%s",str);
int u,v;
u=str[0]-'a';
vis[u]=1;
v=str[strlen(str)-1]-'a';
vis[v]=1;
Union(u,v);
out[u]++; //u->v
in[v]++;
}
int suc=1;
int t;
for(i=0;!vis[i];++i);
t=find(i);
for(;i<26;++i) //判断有向图是否连通
{
if(vis[i]&&t!=find(i))
{
suc=0;
break;
}
}
if(suc)
{
int st=0,ed=0;
for(i=0;i<26;++i)
{
if(vis[i]&&in[i]!=out[i])
{
if(out[i]==in[i]+1)
st++;
else if(in[i]==out[i]+1)
ed++;
else
{
suc=0;
break;
}
}
}
if( !(st==0&&ed==0) && !(st==1&&ed==1) )
suc=0;
}
if(suc)
printf("Ordering is possible.\n");
else
printf("The door cannot be opened.\n");
}
return 0;

}

posted on 2012-03-29 16:25  sysu_mjc  阅读(399)  评论(0编辑  收藏  举报

导航