题意:给你一片“森林”,森林中的树不一定是同构的,现在让你在这些树种至多去掉一条边,使这些树均同构。
做法:参考大牛的,可是代码研究了许久,还是有点心得,所以只能无聊地写下原创。
小于操作符只允许传入一个参数。
#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; }