给定两棵同构的树,要求输出对应的点对。
Hash
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cassert>
#include<cstdio>
#include<bitset>
#include<queue>
#include<cmath>
#include<ctime>
#include<map>
#define inf (1<<30)
#define INF (1ll<<62)
#define fi first
#define se second
#define prt(x) cout<<#x<<":"<<x<<" "
#define prtn(x) cout<<#x<<":"<<x<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
template<class T>void sc(T &x){
int f=1;x=0;char c;
while(c=getchar(),c<48)if(c=='-')f=-1;
do x=x*10+(c^48);
while(c=getchar(),c>47);
x*=f;
}
template<class T>void nt(T x){
if(!x)return;
nt(x/10);putchar('0'+x%10);
}
template<class T>void pt(T x){
if(x<0)putchar('-'),x=-x;
if(!x)putchar('0');
else nt(x);
}
int n;
const int maxn=100005;
int last[2][maxn],ecnt;
struct Edge{
int to,nxt;
Edge(){}
Edge(int a,int b):to(a),nxt(b){}
}e[maxn<<2];
void ins(int *last,int u,int v){
e[ecnt]=Edge(v,last[u]);
last[u]=ecnt++;
}
struct abcd{
vector<string>a;
map<string,int>b;
void init(){
a.clear();
b.clear();
}
int operator [] (string c){
if(b.find(c)!=b.end())return b[c];
a.push_back(c);
return b[c]=a.size();;
}
string operator [] (int c){
return a[c-1];
}
}name;
ii RT;
int sz[maxn];
void dfs(int *last,int x,int f){
sz[x]=1;
bool ok=true;
for(int i=last[x];i!=-1;i=e[i].nxt){
int to=e[i].to;
if(to==f)continue;
dfs(last,to,x);
ok&=sz[to]<=n/2;
sz[x]+=sz[to];
}ok&=(n-sz[x])<=n/2;
if(!ok)return;
if(RT.fi==-1)RT.fi=x;
else RT.se=x;
}
void find_rt(int *last){
RT.fi=RT.se=-1;
dfs(last,1,0);
}
int has[2][maxn];//val,id
int H[maxn];
int link[maxn];
const int Pa=674679;//4679
const int Pb=165537;//65537
const int Pp=435617;//35617
const int Pq=1000000033;
void gethash(int *has,int *last,int x,int f){
for(int i=last[x];i!=-1;i=e[i].nxt){
int to=e[i].to;
if(to!=f)gethash(has,last,to,x);
}
int tot=0;
for(int i=last[x];i!=-1;i=e[i].nxt){
int to=e[i].to;
if(to!=f)H[++tot]=has[to];
}
sort(H+1,H+tot+1);
ll res=Pa;
for(int i=1;i<=tot;i++)
res=(res*Pp^H[i])%Pq;
res=res*Pb%Pq;
has[x]=res;
}
ii HA[maxn],HB[maxn];
bool chk(int x,int fx,int y,int fy){
int na,nb;na=nb=0;
for(int i=last[0][x];i!=-1;i=e[i].nxt){
int to=e[i].to;
if(to==fx)continue;
HA[++na]=ii(has[0][to],to);
}
for(int i=last[1][y];i!=-1;i=e[i].nxt){
int to=e[i].to;
if(to==fy)continue;
HB[++nb]=ii(has[1][to],to);
}
if(na!=nb)return false;
sort(HA+1,HA+na+1);
sort(HB+1,HB+nb+1);
for(int i=1;i<=na;i++){
if(HA[i].fi!=HB[i].fi)return false;
link[HA[i].se]=HB[i].se;
}
for(int i=last[0][x];i!=-1;i=e[i].nxt){
int to=e[i].to;
if(to==fx)continue;
if(!chk(to,x,link[to],y))return false;
}
return true;
}
bool match(int x,int y){
gethash(has[0],last[0],x,0);
gethash(has[1],last[1],y,0);
if(has[0][x]!=has[1][y])return false;
link[x]=y;
return chk(x,0,y,0);
}
void output(){
for(int i=1;i<=n;i++)
cout<<name[i]<<" "<<name[link[i]]<<endl;
}
void solve(){
string u,v;
name.init();
ecnt=0;
for(int i=0;i<2;i++){
memset(last[i],-1,n+1<<2);
for(int a,b,j=1;j<n;j++){
cin>>u>>v;
a=name[u];
b=name[v];
ins(last[i],a,b);
ins(last[i],b,a);
}
}
ii rt[2];
for(int i=0;i<2;i++){
find_rt(last[i]);
rt[i]=RT;
}
// for(int i=0;i<2;i++)
// prt(rt[i].fi),prtn(rt[i].se);
if(match(rt[0].fi,rt[1].fi))output();
else if(match(rt[0].fi,rt[1].se))output();
else puts(":{");
}
int main(){
// freopen("pro.in","r",stdin);
// freopen("chk.out","w",stdout);
while(~scanf("%d",&n))solve();//*INF
return 0;
}
以及造数据的程序 :{
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cassert>
#include<cstdio>
#include<bitset>
#include<queue>
#include<cmath>
#include<ctime>
#define inf (1<<30)
#define INF (1ll<<62)
#define prt(x) cout<<#x<<":"<<x<<" "
#define prtn(x) cout<<#x<<":"<<x<<endl
using namespace std;
typedef long long ll;
template<class T>void sc(T &x){
int f=1;x=0;char c;
while(c=getchar(),c<48)if(c=='-')f=-1;
do x=x*10+(c^48);
while(c=getchar(),c>47);
x*=f;
}
template<class T>void nt(T x){
if(!x)return;
nt(x/10);putchar('0'+x%10);
}
template<class T>void pt(T x){
if(x<0)putchar('-'),x=-x;
if(!x)putchar('0');
else nt(x);
}
const int n=100000;
struct Edge{
int u,v;
}edge[n+5];
int f[n+5];
int Rand(){
return rand()<<15|rand();
}
int main(){
srand(time(0));
freopen("pro.in","w",stdout);
printf("%d\n",n);
for(int i=2;i<=n;i++)
edge[i]=(Edge){Rand()%(i-1)+1,i};
for(int i=2;i<=n;i++)
printf("%d %d\n",edge[i].u,edge[i].v);
for(int i=1;i<=n;i++)
f[i]=i,swap(f[i],f[Rand()%i+1]);
for(int i=1;i<=100000;i++){
int u=Rand()%n+1,v=Rand()%n+1;
if(u!=1&&v!=1)swap(edge[u],edge[v]);
}
for(int i=2;i<=n;i++){
printf("%d %d\n",f[edge[i].u],f[edge[i].v]);
}
return 0;
}
启发式合并+树的最小表示法