zoukankan      html  css  js  c++  java
  • [HAOI2015]树上染色

    Description:

    有一棵点数为 N 的树,树边有边权。给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 。 将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的距离的和的受益。问受益最大值是多少。

    Hint:

    (n le 2^3)

    Solution:

    很好的树型dp题

    设状态(f[i][j])表示i点子树染j个黑点的最大距离和

    然而无法转移

    换一种角度,考虑每条边对答案的贡献

    设一条边的下面一端u的子树中有k个黑点

    (Ans=k*(m-k)+(sz[u]-k)*(n-sz[u]-m+k))

    这样就能用树型背包做了

    #include <map>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ls p<<1 
    #define rs p<<1|1
    using namespace std;
    typedef long long ll;
    const int mxn=1e5+5;
    int n,m,cnt,hd[mxn],sz[mxn];
    ll f[2005][2005];
    
    inline int read() {
        char c=getchar(); int x=0,f=1;
        while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
        while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
        return x*f;
    }
    inline void chkmax(int &x,int y) {if(x<y) x=y;}
    inline void chkmin(int &x,int y) {if(x>y) x=y;}
    
    struct ed {
        int to,nxt,w;
    }t[mxn<<1];
    
    inline void add(int u,int v,int w) {
        t[++cnt]=(ed) {v,hd[u],w}; hd[u]=cnt;
    }
    
    void dfs(int u,int fa) 
    {
        sz[u]=1; f[u][0]=f[u][1]=0;
        for(int i=hd[u];i;i=t[i].nxt) {
            int v=t[i].to;
            if(v==fa) continue ;
            dfs(v,u); sz[u]+=sz[v];
            for(int j=min(m,sz[u]);j>=0;--j) { 
                if(f[u][j]!=-1)
                f[u][j]+=f[v][0]+1ll*sz[v]*(n-m-sz[v])*t[i].w; //这里一定要先处理v为0的答案,如果在后面转移就会错
                for(int k=min(j,sz[v]);k;--k) {
                    if(f[u][j-k]==-1) continue ;
                    ll val=1ll*(k*(m-k)+(sz[v]-k)*(n-m-sz[v]+k))*t[i].w;
                    f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+val);
                }
            }
        }
    }
    
    int main()
    {
        memset(f,-1,sizeof(f));
        n=read(); m=read(); int u,v,w;
        for(int i=1;i<n;++i) {
            u=read(); v=read(); w=read();
            add(u,v,w); add(v,u,w);
        }
        dfs(1,1);
        printf("%lld",f[1][m]);
        return 0;
    }
    
    
  • 相关阅读:
    爬虫流程
    康哥笔记
    csdn笔记
    数据库多表联查
    完整数据恢复
    Linux安装mysql
    linux在vm下实现桥接模式
    Linux下ntpdate时间同步
    spark集群在执行任务出现nitial job has not accepted any resources; check your cluster UI to ensure that worker
    flume在启动时出现brokerList must contain at least one Kafka broker
  • 原文地址:https://www.cnblogs.com/list1/p/10555360.html
Copyright © 2011-2022 走看看