题目的大意是,给出一些单词,问能否拼接成一串,使单词字母首尾相连。例如,Sample中的:
acm
malform
mouse
我们可以构造出:
acm->malform->mouse,符合题目要求。
明显,我们可以构造一个图来解决这个问题。以字母作为结点,则如果存在单词,例如acm,那么a和m就连一条边,同样,对于malform,我们就连一条环在m上。这个时候还可以统计点的出度和入度数。
这是一个欧拉路问题,只要图中存在欧拉回路或者欧拉通路,都符合题目要求。关于判断一个图属否存在欧拉路或欧拉回路,有如下定理:
定理 有向图G为欧拉图,当且仅当G的基图 连通,且所有顶点的入度等于出度。
推论 有向图G为半欧拉图,当且仅当G的基图连通,且存在顶点u的入度比出度大1、v的入度比出度小1,其它所有顶点的入度等于出度。
可以使用dfs判断图的连通性。
因此,我们先必须通过dfs判断整个图是否连通,不连通就没戏了。连通后,再扫一次入度出度的情况即可。下面是代码:
// 1386.cpp : 定义控制台应用程序的入口点。 //思路要清晰,这样才能把题做出来。 //欧拉回路 #include "stdafx.h" #include<iostream> #include<cstring> using namespace std; const int N=26; typedef struct{ int in,out; }GRAPH; int v[N],linked; int g[N][N]; void dfs(int index)//找出节点的个数。那么这里也可以用并查集做了呢。 { //就是判断是不是连通。 v[index]=1; for(int i=0;i<N;i++) if(!v[i]&&g[i][index]) dfs(i); linked++; } int main() { int T,n,i,j; char cmd[1005]; GRAPH degree[N]; scanf("%d",&T); while(T--) { memset(degree,0,sizeof(degree)); memset(g,0,sizeof(g)); scanf("%d",&n); while(n--) { int p1,p2; scanf("%s",cmd); int len=strlen(cmd); p1=cmd[0]-'a'; p2=cmd[len-1]-'a'; degree[p1].out++; degree[p2].in++; g[p1][p2]=g[p2][p1]=1; } memset(v,0,sizeof(v)); int first=0,np=0; for(i=0;i<N;i++) if(degree[i].in||degree[i].out) { //if(!first) first=i;//这里拿到第一个节点就行,不必要判断是不是非零!!! np++; } linked=0; dfs(first); if(linked!=np)//np是有多少节点,linked也是,如果相等,则他们是连通的。 { cout<<"The door cannot be opened."<<endl; continue; } int na=0,nb=0,ne=0,nt=0; for(i=0;i<N;i++) { if(degree[i].in==0&°ree[i].out==0) continue; nt++; if(degree[i].in-degree[i].out==1) na++; else if(degree[i].in-degree[i].out==-1) nb++; else if(degree[i].in==degree[i].out) ne++; } if(na==1&&nb==1&&ne==nt-2||ne==nt)//是欧拉回路的两个条件,要么是全部是一样的开始和结束字母, //要么是是有两个节点的入度和出度之差是一。 cout<<"Ordering is possible."<<endl; else cout<<"The door cannot be opened."<<endl; } system("pause"); return 0; }