标签:
题意:给出给出n个单词,要求判断这些单词能否接龙,规则像成语接龙一样,就是当前单词的尾字母为下一个单词的首字母。
思路:看着像是欧拉通路相关的题目,但是重点就在于怎么抽象出来。
刚开始想了半天没想明白,老想着一个单词作为一个顶点去了,就是没转过来。
看了篇解题报告(http://blog.csdn.net/niushuai666/article/details/6917777) 后想过来了,
应该把单词的首尾字母看成顶点,而这个单词相当于连接顶点的有向边。然后这样想的话,这个图最多就有26个顶点(因为只有26个小写字母,题目要求单词为小写字母),接下来就是怎么判断这个途中是否存在欧拉通路了(即判断是否为半欧拉图或欧拉图)。
关于欧拉图的相关知识,详见:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define MAXN 26//最多26个点 int fa[MAXN]; bool exist[MAXN];//标记点是否存在 int in[MAXN],out[MAXN];//入度,出度 int diff[MAXN];//入度不等于出度的点 int set_find(int d){ if(fa[d]<0)return d; return fa[d]=set_find(fa[d]); } void set_join(int x,int y){ x=set_find(x); y=set_find(y); if(x!=y)fa[x]=y; } int main(){ int t,n,i; char word[1024];//单词 int a,b;//首字母,尾字母 int root;//根节点数目 int m;//入度不等于出度的点的个数 scanf("%d",&t); while(t--){ memset(fa,-1,sizeof(fa)); memset(exist,0,sizeof(exist)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); root=0; m=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]; set_join(b,a);//b连到a上 } for(i=0;i<MAXN;++i) if(exist[i]&&fa[i]<0)++root; if(root>1)printf("The door cannot be opened.\n");//图不连通 else{ for(i=0;i<MAXN;++i) if(in[i]!=out[i])diff[m++]=i; if(m==0)printf("Ordering is possible.\n");//所有点入度等于出度,为欧拉图 else if(m==2&&( (in[diff[0]]-out[diff[0]]==1&&out[diff[1]]-in[diff[1]]==1)|| (out[diff[0]]-in[diff[0]]==1&&in[diff[1]]-out[diff[1]]==1) ) )printf("Ordering is possible.\n");//满足半欧拉图条件,为半欧拉图 else printf("The door cannot be opened.\n");//不是欧拉图,也不是半欧拉图 } } return 0; }
标签:
原文地址:http://www.cnblogs.com/bofengyu/p/4731095.html