• 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
    ",(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
    ",ans);
            }
    
        }
        return 0;
    }
  • 相关阅读:
    IDEA小插件之快速修改Maven多模块的工程版本
    Java 8 Lambda实现原理分析
    怒学Java8系列一:Lambda表达式
    Redis有序集内部实现原理分析(二)
    Redis有序集内部实现原理分析
    JVM内存堆布局图解分析
    Redis内存回收:LRU算法
    垃圾收集器:引用计数算法
    Maven解读:项目依赖管理如何优化
    Maven解读:强大的依赖体系
  • 原文地址:https://www.cnblogs.com/zufezzt/p/6429342.html
Copyright © 2020-2023  润新知