这个题目要运用到欧拉路得相关知识,并且也要并查集,题目说的是:给你n个单词,要你判断这些单词能不能首尾相连。理解题目意思后,进行转化,输入字符串,提取首位字母作为下标来表示两节点的出现,以及相对应节点入度和出度的增加,转化为并查集的应用即可。那么从可以想象一幅由首位字母节点构成的图,当且仅当图是一条欧拉回路或者欧拉通路的时候,才能满足题目的要求,至于欧拉回路和欧拉通路的判定可以总结为如下:
1)所有的点联通
2)欧拉回路中所有点的入度和出度一样。
1)所有的点联通
2)欧拉回路中所有点的入度和出度一样。
3)欧拉通路中起点的入度 - 出度 = 1,终点的 初度 - 入度 = 1, 其他的所有点入度 = 出度;
无向图存在欧拉回路条件
一个无向图存在欧拉回路,当且仅当该图所有顶点度数都是偶数。有向图存在欧拉回路条件
一个有向图存在欧拉回路,且所有顶点的入度等于出度
#include<stdio.h>
#include<string.h>
#include<math.h>
#define N 30
int father[N],vis[N];
//father[i] 表示节点 i 的 BOSS ! vis[i]表示节点 i 出现过
int findx(int x)
{ //找节点 x 的 BOSS !
if(father[x]!=x)
father[x]=findx(father[x]);
return father[x];
}
void merge(int a,int b)
{ // 合并 节点 a 和节点 b
int x,y;
x=findx(a);
y=findx(b);
if(x!=y) father[x]=y;
}
int main()
{
int text,cnt,i,j,n,out[N],in[N],p[30],a,b;
char str[1001];
scanf("%d",&text);
while(text--)
{
scanf("%d",&n);
memset(out,0,sizeof(out));
memset(in,0,sizeof(in));
memset(vis,0,sizeof(vis));
for(i=0;i<26;i++)
father[i]=i; //初始化数组
while(n--)
{ // 处理所给信息 !
scanf("%s",str);
a=str[0]-'a';
b=str[strlen(str)-1]-'a';
merge(a,b);
out[a]++;
in[b]++; // 记录节点 a 和 b的入度和出度
vis[a]=1;
vis[b]=1; //标记节点 a 和 b的出现
}
for(i=0;i<26;i++)
father[i]=findx(i); //找出每个节点的 BOSS
for(cnt=0,i=0;i<26;i++)
if(vis[i] && father[i]==i)
cnt++; // 统计最终 BOSS 即根节点的个数 。
if(cnt>1) //图不连通
{
printf("The door cannot be opened.\n");
continue;
}
for(j=0,i=0;i<26;i++)
if(vis[i] && out[i]!=in[i])
p[j++]=i; //统计入度和出度不相等的点的信息
if(j==0)
{//欧拉回路,即环
printf("Ordering is possible.\n");
continue;
}
if(j==2 && ( out[p[0]]-in[p[0]]==1 && in[p[1]]-out[p[1]]==1
|| out[p[1]]-in[p[1]]==1 && in[p[0]]-out[p[0]]==1 ) )
{//欧拉通路
printf("Ordering is possible.\n");
continue;
}
printf("The door cannot be opened.\n");
}
return 0;
}