ZOJ 3330 Country F 无根树同构

题意:给你一片“森林”,森林中的树不一定是同构的,现在让你在这些树种至多去掉一条边,使这些树均同构。

做法:参考大牛的,可是代码研究了许久,还是有点心得,所以只能无聊地写下原创。

小于操作符只允许传入一个参数。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<climits>
#define LMT 10003
#define mod 15237
/*我终于知道昨天的问题了,同构树的拓扑序列一定相同,
可是无根树时,
因为最后一条边的拓扑顺序的问题可能会导致根节点的位置不同,
所以要搞两个根节点,两次哈希判断同构,跪下了...*/
/*因为是无向图,所以图中一开始不一定会存在度数为0的,为了让哈希能够顺利进行,所以
所以要取度数为1的入队*/
using namespace std;
class tree
{
public:
	int one,two,h1,h2,num;
	bool operator <(const tree &b)const
	{
		if(b.num)return num<b.num;
		if(h1!=b.h1)return h1<b.h1;
		return h2<b.h2;
	}
	int operator ==(const tree &b)
	{
		return h1==b.h1&&h2==b.h2;
	}
}t[LMT];
vector<int>gra[LMT];
int num[LMT],que[LMT],du[LMT],hash[LMT],havein[LMT],pre[LMT];
int id,st,ed,pa,pb;
void swap(int &a,int &b)
{
	int t=a;
	t=a;
	a=b;
	b=t;
}
void dfs(int u,int pri)
{
	size_t i,len;
	pre[u]=pri;
	t[id].num++;num[u]=1;
	havein[u]=id;
	len=du[u]=gra[u].size();
	if(u==pa||u==pb)du[u]--;
	if(du[u]==1||du[u]==0)que[ed++]=u;
	for(i=0;i<len;i++)
		if(pri!=gra[u][i])
		{
			dfs(gra[u][i],u);
			num[u]+=num[gra[u][i]];
		}
}
void topo(int x)
{
	int k,sum=t[x].num,u,v;
	size_t len,i;
	while(st<ed)
	{
		if(sum==2)
		{
			t[x].one=que[st];
			t[x].two=que[st+1];
			return;
		}
		else if(sum==1)
		{
			t[x].one=que[st];
			t[x].two=-1;
			return ;
		}
		k=ed;
		while(st<k)
		{
			u=que[st++];sum--;len=gra[u].size();
			for(i=0;i<len;i++)
			{
				v=gra[u][i];
				if(u==pa&&v==pb)continue;
				if(u==pb&&v==pa)continue;
				du[v]--;
				if(du[v]==1)que[ed++]=v;
			}
		}
	}
}
int hdfs(int u,int pre)
{
	int v,ret=1;
	int i,len;
	vector<int>e;e.clear();
	len=gra[u].size();
	for(i=0;i<len;i++)
	if(gra[u][i]!=pre)
	{
		v=gra[u][i];
		if(u==pa&&v==pb)continue;
		if(v==pa&&u==pb)continue;
		e.push_back(hdfs(v,u));
	}
	if(e.size()==0)return 1;
	sort(e.begin(),e.end());
	len=e.size();
	for(i=0;i<len;i++)
	ret=(ret*e[i])^hash[i]%mod;
	return ret%mod;
}
int main(void)
{
	int n,m,u,v,no,i;
	for(i=0;i<LMT;i++)
		hash[i]=rand()%mod;
	while(scanf("%d%d",&n,&m),n+m)
	{
		for(i=0;i<n;i++)gra[i].clear();
		for(i=0;i<m;i++)
		{
			scanf("%d%d",&u,&v);
			gra[u].push_back(v);
			gra[v].push_back(u);
		}
		memset(havein,-1,sizeof(havein));
		pa=pb=-1;id=0;
		for(i=0;i<n;i++)
			if(havein[i]==-1)
			{
				st=ed=0;t[id].num=0;dfs(i,-1);
				topo(id);
				t[id].h1=hdfs(t[id].one,-1);
				if(t[id].two>=0)t[id].h2=hdfs(t[id].two,-1);
				else t[id].h2=-1;
				if(t[id].h1<t[id].h2)swap(t[id].h1,t[id].h2);
				id++;
			}
			sort(t,t+id);
			no=0;
			for(i=1;i<id;i++)no=!(t[i]==t[i-1]);
			if(!no)
			{
				printf("Yes\n");
				continue;
			}
			no=0;
			for(i=1;i<id-1;i++)no=!(t[i-1]==t[i]);
			if(no)
			{
				printf("No\n");
				continue;
			}
			for(i=0;i<n;i++)
			if(num[i]==t[0].num&&~pre[i])
			{
				pa=i;
				pb=pre[i];
				break;
			}
			id--;
			st=ed=0;t[id].num=0;dfs(pa,pb);
			topo(id);t[id].h1=hdfs(t[id].one,-1);
			if(~t[id].two)t[id].h2=hdfs(t[id].two,-1);
			else t[id].h2=-1;
			if(t[id].h1<t[id].h2)swap(t[id].h1,t[id].h2);
			id++;swap(pa,pb);
			st=ed=0;t[id].num=0;dfs(pa,pb);
			topo(id);t[id].h1=hdfs(t[id].one,-1);
			if(~t[id].two)t[id].h2=hdfs(t[id].two,-1);
			else t[id].h2=-1;
			if(t[id].h1<t[id].h2)swap(t[id].h1,t[id].h2);
			id++;
			if(t[id-1]==t[id-2]&&t[id-1]==t[0])printf("Yes\n");
			else printf("No\n");
	}
	return 0;
}


 

你可能感兴趣的:(ZOJ 3330 Country F 无根树同构)