zoj 2016 Play on Words 欧拉回路
题目大意:给出一些单词,问能否摆成类似成语接龙的顺序(即前一个单词的最后一个字母要和下一个单词首字母相同)。
对于每个单词,只有首尾两字母重要,该单词可看做由首字母到尾字母的一条边,即所有单词的首尾两字母看做图中节点,每个单词可看做一条边,构造好有向图后,若要摆成题意要求的顺序,即判断是否存在欧拉回路即可。
#include <stdio.h>
#include <string.h>
int t,n;
char word[1001];//存储每个单词
int od[30],id[30];//每个顶点的出度和入度
int bused[30],p[30];//bused表示该顶点是否存在,p是并查集中的父节点
struct edge
{
int u,v;
}edges[100010];
void init()
{
int i;
for(i=0;i<26;i++)
p[i]=i;
}
int get(int x)
{
if(p[x]==x)
return x;
else
return p[x]=get(p[x]);
}
bool con()
{
int u,v,i;
init();
for(i=0;i<n;i++)
{
u=edges[i].u;
v=edges[i].v;
u=get(u);
v=get(v);
if(u!=v)
p[u]=v;
}
int sum=0;
for(i=0;i<26;i++)
{
if(bused[i]==0)continue;
if(p[i]==i)
sum++;
}
if(sum>1)
return false;
else
return true;
}
int main()
{
int u,v;
int i,j;
scanf("%d",&t);
for(i=0;i<t;i++)
{
memset(bused,0,sizeof(bused));
memset(od,0,sizeof(od));
memset(id,0,sizeof(id));
scanf("%d",&n);
for(j=0;j<n;j++)
{
scanf("%s",word);
u=word[0]-'a';v=word[strlen(word)-1]-'a';
od[u]++;id[v]++;
bused[u]=bused[v]=1;
edges[j].u=u;edges[j].v=v;
}
bool euler=true;
int one=0;
int none=0;
for(j=0;j<26;j++)
{
if(bused[j]==0)continue;
if(od[j]-id[j]>1||id[j]-od[j]>1) {euler=false;break;}
if(od[j]-id[j]==1)
{
one++;
if(one>1) {euler=false;break;}
}
if(id[j]-od[j]==1)
{
none++;
if(none>1) {euler=false;break;}
}
}
if(one!=none)
euler=false;
if(!con()) euler=false;
if(euler) printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");
}
return 0;
}

浙公网安备 33010602011771号