zoj 2016 Play on Words 欧拉回路

题目大意:给出一些单词,问能否摆成类似成语接龙的顺序(即前一个单词的最后一个字母要和下一个单词首字母相同)。

对于每个单词,只有首尾两字母重要,该单词可看做由首字母到尾字母的一条边,即所有单词的首尾两字母看做图中节点,每个单词可看做一条边,构造好有向图后,若要摆成题意要求的顺序,即判断是否存在欧拉回路即可。

#include <stdio.h>
#include <string.h>
int t,n;
char word[1001];//存储每个单词
int od[30],id[30];//每个顶点的出度和入度
int bused[30],p[30];//bused表示该顶点是否存在,p是并查集中的父节点
struct edge
{
	int u,v;
}edges[100010];
void init()
{
	int i;
	for(i=0;i<26;i++)
		p[i]=i;
}
int get(int x)
{
	if(p[x]==x)
		return x;
	else
		return p[x]=get(p[x]);
}

bool con()
{
	int u,v,i;
	init();
	for(i=0;i<n;i++)
	{
		u=edges[i].u;
		v=edges[i].v;
		u=get(u);
		v=get(v);
		if(u!=v)
			p[u]=v;
	}
	int sum=0;
	for(i=0;i<26;i++)
	{
		if(bused[i]==0)continue;
		if(p[i]==i)
			sum++;
	}
	if(sum>1)
		return false;
	else
		return true;
}

int main()
{
	int u,v;
	int i,j;
	scanf("%d",&t);
	for(i=0;i<t;i++)
	{
		memset(bused,0,sizeof(bused));
		memset(od,0,sizeof(od));
		memset(id,0,sizeof(id));
		scanf("%d",&n);
		for(j=0;j<n;j++)
		{
			scanf("%s",word);
			u=word[0]-'a';v=word[strlen(word)-1]-'a';
			od[u]++;id[v]++;
			bused[u]=bused[v]=1;
			edges[j].u=u;edges[j].v=v;
		}
		bool euler=true;
		int one=0;
		int none=0;
		for(j=0;j<26;j++)
		{
			if(bused[j]==0)continue;
			if(od[j]-id[j]>1||id[j]-od[j]>1) {euler=false;break;}
			if(od[j]-id[j]==1)
			{
				one++;
				if(one>1) {euler=false;break;}
			}
			if(id[j]-od[j]==1)
			{
				none++;
				if(none>1) {euler=false;break;}
			}
		}
		if(one!=none)
			euler=false;
		if(!con()) euler=false;
		if(euler) printf("Ordering is possible.
");
		else printf("The door cannot be opened.
");
	}
	return 0;
}


 

原文地址:https://www.cnblogs.com/vermouth/p/3710215.html