首页 > 代码库 > HDU 4863 Centroid of a Tree

HDU 4863 Centroid of a Tree

树的重心,树形$dp$,背包。

树的重心有两个充分必要条件:

$1$.某树有两个重心$a$,$b$ $<=>$ $a$与$b$相邻,断开$a$与$b$之间的边之后,两个联通分量内的点的个数相同。

$2$.某树有一个重心$a$ $<=>$ 以$a$为根的树,去掉a之后,剩下的联通分量,除去节点个数最多的联通分量后,剩余的联通分量节点个数之和大于等于最大的联通分量的节点个数。

因此,可以先计算出初始树的重心,分两种情况讨论。

如果有两个重心$a$,$b$,那么,我们需要计算出断开$a$,$b$之间的边,以$a$为根的树以及以$b$为根的树中包含$x$个节点的树有几种,然后枚举$x$两边相乘求和就是答案了。

如果只有一个重心$a$,这种情况比两个重心的复杂一点,需要计算以$a$为根的树有多少种满足充要条件$2$,先要计算出以$a$的儿子为根的树中包含$x$个节点的树有几种,然后再用背包去算一下反面的情况,总的方案减去反面的就是答案。

#pragma comment(linker, "/STACK:1024000000,1024000000")#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#include<map>#include<set>#include<queue>#include<stack>#include<ctime>#include<iostream>using namespace std;typedef long long LL;const double pi=acos(-1.0);void File(){    freopen("D:\\in.txt","r",stdin);    freopen("D:\\out.txt","w",stdout);}template <class T>inline void read(T &x){    char c = getchar();    x = 0;    while(!isdigit(c)) c = getchar();    while(isdigit(c))    {        x = x * 10 + c - 0;        c = getchar();    }}int T,n;int mod=10007;int dp[205][205];int c[205],mx[205],k[205],f[205];vector<int>tmp[205],t[205],zx;void init(){    memset(dp,0,sizeof dp);    memset(c,0,sizeof c);    memset(mx,0,sizeof mx);    memset(f,0,sizeof f);    for(int i=1;i<=n;i++) tmp[i].clear();    for(int i=1;i<=n;i++) t[i].clear();    zx.clear();}void D(int x){    f[x]=1;    for(int i=0;i<tmp[x].size();i++)    {        if(f[tmp[x][i]]) continue;        t[x].push_back(tmp[x][i]);        D(tmp[x][i]);    }}void F(int x){    for(int i=0;i<t[x].size();i++)    {        F(t[x][i]);        mx[x]=max(mx[x],c[t[x][i]]);        c[x]=c[x]+c[t[x][i]];    }    c[x]++;}void G(int x){    f[x]=1;    for(int i=0;i<tmp[x].size();i++)    {        if(f[tmp[x][i]]) continue;        if(zx.size()==2&&tmp[x][i]==zx[1]) continue;        t[x].push_back(tmp[x][i]);        G(tmp[x][i]);    }}void DP(int x){    dp[x][0]=1; int h[250],g[250];    memset(h,0,sizeof h); memset(g,0,sizeof g);    g[0]=1;    for(int i=0;i<t[x].size();i++)    {        DP(t[x][i]);        for(int j=0;j<=c[x]+c[t[x][i]];j++) h[j]=0;        for(int p1=c[x];p1>=0;p1--)            for(int p2=c[t[x][i]];p2>=0;p2--)                h[p1+p2]=(h[p1+p2]+g[p1]*dp[t[x][i]][p2]%mod)%mod;        for(int j=0;j<=c[x]+c[t[x][i]];j++) g[j]=h[j];        c[x]=c[x]+c[t[x][i]];    }    c[x]++;    for(int i=1;i<=200;i++) dp[x][i]=g[i-1];}int main(){    scanf("%d",&T); int cas=1;    while(T--)    {        scanf("%d",&n);        init();        for(int i=1;i<=n-1;i++)        {            int x,y; scanf("%d%d",&x,&y);            tmp[x].push_back(y);            tmp[y].push_back(x);        }        D(1); F(1);        for(int i=1;i<=n;i++) k[i]=max(mx[i],n-c[i]);        int mn=400; for(int i=1;i<=n;i++) mn=min(mn,k[i]);        for(int i=1;i<=n;i++) if(k[i]==mn) zx.push_back(i);        for(int i=1;i<=n;i++) t[i].clear();        memset(f,0,sizeof f);        G(zx[0]); if(zx.size()==2) G(zx[1]);        memset(c,0,sizeof c);        DP(zx[0]); if(zx.size()==2) DP(zx[1]);        printf("Case %d: ",cas++);        int ans=0;        if(zx.size()==1)        {            int h[250],g[250]; int fm=0;            for(int i=0;i<t[zx[0]].size();i++)            {                memset(h,0,sizeof h); memset(g,0,sizeof g); g[0]=1;                int a=0;                for(int j=0;j<t[zx[0]].size();j++)                {                    if(i==j) continue;                    for(int w=0;w<=a+c[t[zx[0]][j]];w++) h[w]=0;                    for(int p1=a;p1>=0;p1--)                        for(int p2=c[t[zx[0]][j]];p2>=0;p2--)                            h[p1+p2]=(h[p1+p2]+g[p1]*dp[t[zx[0]][j]][p2]%mod)%mod;                    a=a+c[t[zx[0]][j]];                    for(int j=0;j<=200;j++) g[j]=h[j];                }                for(int j=0;j<=c[t[zx[0]][i]];j++)                    for(int w=0;w<j;w++)                        fm=(fm+dp[t[zx[0]][i]][j]*g[w]%mod)%mod;            }            for(int i=1;i<=n;i++) ans=(ans+dp[zx[0]][i])%mod;            printf("%d\n",(ans-fm+mod)%mod);        }        else        {            for(int i=1;i<=200;i++)                ans=(ans+dp[zx[0]][i]*dp[zx[1]][i]%mod)%mod;                printf("%d\n",ans);        }    }    return 0;}

 

HDU 4863 Centroid of a Tree