poj 1386 欧拉回路

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

  

你可能感兴趣的:(poj)