POJ1386 Play on Words 欧拉回路[并查集判断连通]

题目大意:

给一些单词,如果某个单词的首字母和另一个单词的尾字母相同,则两个单词可以连接起来。

要求判断能否把全部单词连接起来。


思路:

欧拉通路。

先构图:每个字母为点。然后对每个单词,将单词的首字母和尾字母连一个单向边。

#include<iostream>
using namespace std;
const int N=100005;
char str[1005];
int n;
struct Edge
{
	int v,next;
}edge[N];
int edgehead[30];
int k=1;
int in[30];
int out[30];
bool start[30];
int pre[30];
int num;
int find(int u)
{
	while(pre[u]>0)
	{
		u=pre[u];
	}
	return u;
}
void  Union(int a,int b)
{
	if(pre[a]<pre[b])
	{
		pre[a]+=pre[b];
		pre[b]=a;
	}
	else
	{
		pre[b]+=pre[a];
		pre[a]=b;
	}
}
bool IsEuler()
{
	int ng=0,nl=0,ne=0;
	for(int i=1;i<=26;i++)
	{
		if(start[i])
		{
			if(in[i]==out[i])
			{
				ne++;
			}
			else if(in[i]==out[i]+1)
			{
				ng++;
			}
			else if(in[i]==out[i]-1)
			{
				nl++;
			}
		}
	}
	if((ne+ng+nl==num&&nl==1&&ng==1)||(ne==num))
		return true;
	else
		return false;
}
void addedge(int u,int v)
{
	start[u]=start[v]=1;
	edge[k].v=v;
	edge[k].next=edgehead[u];
	edgehead[u]=k++;
	in[v]++;
	out[u]++;
}
bool Check()
{
	int first=1;
	int fat;
	while(!start[first])
	{
		first++;
	}
	fat=find(first);
	for(int i=first+1;i<=26;i++)
	{
		if(start[i]&&find(i)!=fat)
		{
			return false;
		}
	}
	return true;
}
int main()
{
	int cases;
	scanf("%d",&cases);
	while(cases--)
	{
		k=1;
		memset(pre,-1,sizeof(pre));
		memset(in,0,sizeof(in));
		memset(out,0,sizeof(out));
		memset(start,0,sizeof(start));
		memset(edge,0,sizeof(edge));
		memset(edgehead,0,sizeof(edgehead));
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%s",str);
			int a=str[0]-'a'+1;
			int b=str[strlen(str)-1]-'a'+1;
			addedge(a,b);
			if(find(a)!=find(b))
				Union(find(a),find(b));
		}
		num=0;
		for(int i=1;i<=26;i++)
		{
			if(start[i])
				num++;
		}
		if(!Check())
		{
			printf("The door cannot be opened.\n");
			continue;
		}

		if(IsEuler())	
			printf("Ordering is possible.\n");
		else
			printf("The door cannot be opened.\n");
	}
	return 0;
}


你可能感兴趣的:(POJ1386 Play on Words 欧拉回路[并查集判断连通])