poj1386&poj2513 欧拉回路

------------------------------poj1386和poj2513是同一个类型

POJ1836:

视为求有向的欧拉通路(并非欧拉回路)

判别方法

①所有的点入度==出度或者②只有有两个入度减出度为1和-1的两个节点(终点,开点)其他点入度==出度则存在欧拉通路

由于这题需要用完全部的单词,所以要判断图是否全部连通,即用并查集即可判断有多少个集合。

代码:

/*
	将一个单词的首位和末位视为一个顶点,则中间的单词则是一条边.
	那么只需要记录下首位的出度和末位的入度,数据量就变成了26个.
	用used[]记录下这个字母是否出现
*/
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
bool used[26];
int f[26];
int indegree[26];
int outdegree[26];
inline void read(int &m)//int
{
	int x=0,f=1;char ch=getchar();//int
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	m=x*f;
}
int find(int x)
{
	if(f[x]!=x)
		f[x]=find(f[x]);
	return f[x];
}
bool concect()
{
	int cnt=0;
	for(int i=0;i<26;i++)
		if(used[i]&&f[i]==i)
			cnt++;
	return cnt==1;
}
int main()
{
	int cas,n;
	read(cas);
	while(cas--)
	{
		read(n);
		memset(used,0,sizeof(used));
		memset(indegree,0,sizeof(indegree));
		memset(outdegree,0,sizeof(outdegree));
		for(int i=0;i<26;i++)
			f[i]=i;
		char ch[1010];
		while(n--)
		{
			scanf("%s",ch);
			int a=ch[0]-'a';
			int b=ch[strlen(ch)-1]-'a';
			outdegree[a]++;
			indegree[b]++;
			used[a]=used[b]=1;
			if(find(a)!=find(b))  //Union
				f[find(a)]=find(b);
		}
		int one=0;//出度比入度多一
		int done=0;//入度比出度多一
		bool flag=1;
		for(int i=0;i<26;i++)
		{
			if(!used[i])continue;
			if(indegree[i]-outdegree[i]>=2||outdegree[i]-indegree[i]>=2)  //并不相等且太离谱了了- - 
			{
				flag=0;
				break;
			}
			if(indegree[i]-outdegree[i]==1&&++done>=2)  //检查相差几个单位
			{
				flag=0;
				break;
			}
			if(outdegree[i]-indegree[i]==1&&++one>=2)
			{
				flag=0;
				break;
			}
		}
		if(one!=done)  flag=0;
		if(!concect()) flag=0;  //是否连通
		if(flag)
			printf("Ordering is possible.\n");
		else
			printf("The door cannot be opened.\n");
	}
	return 0;
}

poj2513

视为求无向图欧拉通路

无向图存在欧拉路的充要条件为:

①     图是连通的;

②     所有节点的度为偶数,或者有且只有两个度为奇数的节点。

由于这道题不能用map映射string的id,所以只能用字典树来映射

当然由于还要用完全部的火柴,也需要判断是否全部连通--并查集

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=510010;
int f[maxn];
int degree[maxn];
int color=0;
struct trie
{
	bool flag;
	int id;
	trie *next[26];
	trie()
	{
		for(int i=0;i<26;i++)
			next[i]=NULL;
		flag=0;
		id=0;
	}
};
int insert_get(trie *root,char *ch)
{
	trie *p=root;
	int len=strlen(ch);
	for(int i=0;i<len;i++)
	{
		if(p->next[ch[i]-'a']==NULL)
		{
			trie *temp=new trie;
			p->next[ch[i]-'a']=temp;
		}
		p=p->next[ch[i]-'a'];
	}
	if(!p->flag)
	{
		p->flag=1;
		p->id=++color;
	}
	return p->id;
}
int find(int x)
{
	if(f[x]!=x)
		f[x]=find(f[x]);
	return f[x];
}
int connect()
{
	int cnt=0;
	for(int i=1;i<=color;i++)
		if(f[i]==i)
			cnt++;
	return cnt==1;
}
int main()
{
	trie *root=new trie;
	for(int i=0;i<maxn;i++)
		f[i]=i;
	memset(degree,0,sizeof(degree));
	char st1[20],st2[20];
	bool ok=1;  //这道题有空数据,在空数组这wa一次。特别标志一下
	while(~scanf("%s %s",st1,st2))
	{
		ok=0;
		int a=insert_get(root,st1);
		int b=insert_get(root,st2);
		degree[a]++;
		degree[b]++;
		if(find(a)!=find(b))
			f[find(a)]=find(b);
	}
	int one=0;//度为奇数的节点个数
	bool flag=1;
	for(int i=1;i<=color;i++)
		if(degree[i]%2==1)
			one++;
	if(ok||(connect()&&(one==0||one==2)))
		printf("Possible\n");
	else
		printf("Impossible\n");
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值