题目的大意是,给出一些单词,问能否拼接成一串,使单词字母首尾相连。例如,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;
}