题意:给出给出n个单词,要求判断这些单词能否接龙,规则像成语接龙一样,就是当前单词的尾字母为下一个单词的首字母。
思路:看着像是欧拉通路相关的题目,但是重点就在于怎么抽象出来。
刚开始想了半天没想明白,老想着一个单词作为一个顶点去了,就是没转过来。
看了篇解题报告(http://blog.csdn.net/niushuai666/article/details/6917777) 后想过来了,
应该把单词的首尾字母看成顶点,而这个单词相当于连接顶点的有向边。然后这样想的话,这个图最多就有26个顶点(因为只有26个小写字母,题目要求单词为小写字母),接下来就是怎么判断这个途中是否存在欧拉通路了(即判断是否为半欧拉图或欧拉图)。
关于欧拉图的相关知识,详见:
代码:
思路:看着像是欧拉通路相关的题目,但是重点就在于怎么抽象出来。
刚开始想了半天没想明白,老想着一个单词作为一个顶点去了,就是没转过来。
看了篇解题报告(http://blog.csdn.net/niushuai666/article/details/6917777) 后想过来了,
应该把单词的首尾字母看成顶点,而这个单词相当于连接顶点的有向边。然后这样想的话,这个图最多就有26个顶点(因为只有26个小写字母,题目要求单词为小写字母),接下来就是怎么判断这个途中是否存在欧拉通路了(即判断是否为半欧拉图或欧拉图)。
关于欧拉图的相关知识,详见:
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int in[26],out[26];//入度,出度
int differ[10];//入度不同的顶点
bool exist[26];//记录字母是否存在
int set[26];//父亲节点
int root;//根的数目
int set_find(int d){
if(set[d]<0)
return d;
return set[d]=set_find(set[d]);
}
void join(int x,int y){ //采用路径压缩的并查集,判断是否连通
x=set_find(x);
y=set_find(y);
if(x!=y) set[x]=y;
return;
}
int main(){
int t;//测试个数
int n;//单词个数
int i;//
int number;//入度不同的顶点的个数
char word[1100];//存放单词
int a,b;
scanf("%d",&t);
while(t--){
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(set,-1,sizeof(set));
memset(exist,0,sizeof(exist));
number=0;
root=0;
scanf("%d",&n);
while(n--){
scanf("%s",word);
a=word[0]-'a';
b=word[strlen(word)-1]-'a';
exist[a]=exist[b]=true;
out[a]++;
in[b]++;
join(b,a);
}
for(i=0;i<26;i++){
if(exist[i]&&set[i]<0)
root++;
}
if(root>1)//图不连通
printf("The door cannot be opened.\n");
else{
for(i=0;i<26;i++){
if(in[i]!=out[i])
differ[number++]=i;
}
if(number==0) //所有顶点入度等于出度,为欧拉图
printf("Ordering is possible.\n");
else if( number==2 && ( //注意&&、||的优先级,此处要加括号
(in[differ[0]]-out[differ[0]]==1 && out[differ[1]]-in[differ[1]]==1)||
(out[differ[0]]-in[differ[0]]==1 && in[differ[1]]-out[differ[1]]==1) )
)//满足半欧拉图条件,为半欧拉图
printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");//不是欧拉图,也不是半欧拉图
}
}
return 0;
}