您的位置:首页 > 其它

HDU 4275 Color the Tree(树同构)

2012-09-22 10:47 309 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4275

题意:给出一个n个节点的树,有m种颜色。问不同的染色方案有多少?

思路:本题首先要解决的就是对称的情况怎么办,网上说要找到树的中心,也就是找到树上的一条最长路,最长路为奇数,则中间一个节点作为根节点,否则,在中间增加一个节点作为根节点使得两边的最长路相等。然后就是树形DP,ans[u]表示以u为根节点的子树的总的染色方案,hash[u]存储以u为根节点的子树的结构。设u节点有k个子节点,v1,v2……vk,首先将子节点按照hash值排序,这样,同构的子树在排序后就会相邻,设有x个子树同构,则这x个子树总的染色方案为C(ans[v]+x-1,x)。这个式子是怎么推出来的我也不清楚,反正试了个ans[v]=2,x=2的是对的。接着就是将这些相乘就得到u节点的ans值,u节点的hash值由子节点的hash值Hash得到。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

struct node
{
int v,next;
};

struct Node
{
__int64 hash,ans;
};

const __int64 mod=1000000007;
const __int64 P=10003;
const __int64 Q=100000037;
node edges[200005];
Node q[50005];
int head[50005],e,E,M,MM,C,f[50005],dp[50005],n;
__int64 hash[100005],ans[100005],p[100005],son[50005];

void Add(int u,int v)
{
edges[e].v=v;
edges[e].next=head[u];
head[u]=e++;
}

__int64 POW(__int64 a,__int64 b)
{
__int64 ans=1;
while(b)
{
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}

__int64 cal(int n,int m)
{
if(n==m) return 1;
__int64 n1=1,n2=p[m],i;
for(i=1;i<=m;i++) n1=n1*(n-i+1)%mod;
return n1*POW(n2,mod-2)%mod;
}

int cmp(Node a,Node b)
{
return a.hash<b.hash;
}

void init()
{
int i;
p[1]=1;
for(i=2;i<=100000;i++) p[i]=p[i-1]*i%mod;
}

int DFS(int u,int pre)
{
int m1=0,m2=0,i,v,t;
for(i=head[u];i!=-1;i=edges[i].next)
{
v=edges[i].v;
if(v==pre) continue;
t=DFS(v,u);
if(t>m1) m2=m1,m1=t,f[u]=i;
else if(t>m2) m2=t;
}
if(M<m1+m2) MM=u,M=m1+m2;
dp[u]=m1;
return dp[u]+1;
}

void DFS1(int u,int pre)
{
int i,j,v;
son[u]=0;

for(i=head[u];i!=-1;i=edges[i].next)
{
v=edges[i].v;
if(v==pre||i==E||i==(E^1)) continue;
ans[v]=C;
DFS1(v,u);
son[u]++;
}
if(!son[u])
{
hash[u]=1;
return;
}
for(j=0,i=head[u];i!=-1;i=edges[i].next)
{
v=edges[i].v;
if(v==pre||i==E||i==(E^1)) continue;
q[j].hash=hash[v];
q[j++].ans=ans[v];
}
sort(q,q+son[u],cmp);
hash[u]=977872;
for(i=0;i<son[u];i++)
{
for(j=i;j<son[u]&&q[i].hash==q[j].hash;j++)
{
hash[u]*=P;
hash[u]^=q[j].hash;
hash[u]%=mod;
}
j--;
ans[u]*=cal(q[i].ans+j-i,j-i+1);
ans[u]%=mod;
i=j;
}
}

int main()
{
init();
while(scanf("%d%d",&n,&C)!=-1)
{
memset(head,-1,sizeof(head));
e=2;
int i,u,v;
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
Add(u,v);
Add(v,u);
}
M=-1;DFS(1,-1);

if(M&1)
{
while(dp[MM]*2>M+1) MM=edges[f[MM]].v;
E=f[MM];
Add(MM,n+1);
Add(n+1,MM);
Add(edges[f[MM]].v,n+1);
Add(n+1,edges[f[MM]].v);
MM=n+1;
ans[MM]=1;
}
else
{
E=0;
while(dp[MM]*2>M) MM=edges[f[MM]].v;
ans[MM]=C;
}
DFS1(MM,-1);
printf("%I64d\n",ans[MM]);
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: