• BZOJ 4033 HAOI2008 树上染色


    4033: [HAOI2015]树上染色

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 2302  Solved: 973
    [Submit][Status][Discuss]

    Description

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

    Input

    第一行两个整数N,K。
    接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to)。
    输入保证所有点之间是联通的。
    N<=2000,0<=K<=N
     

    Output

    输出一个正整数,表示收益的最大值。
     

    Sample Input

    5 2
    1 2 3
    1 5 1
    2 3 1
    2 4 2

    Sample Output

    17
    【样例解释】
    将点1,2染黑就能获得最大收益。

    HINT

    2017.9.12新加数据一组 By GXZlegend 

    Source

    这道题需要知道一个小结论就是树上合并背包的复杂度是O(n^2)的
    接下来就很显然了,我们用f[st][k]来表示以st为根的子树(包括st)选k个黑色节点对答案最大的贡献
    我们来考虑一条边的贡献怎么算呢
     
    很显然A-B这条边对答案的贡献为k*(m-k)*dis[AB]+(siz[A]-k)*(n-siz[A]-m+k)*dis[AB]
    dp做背包即可 
    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x=0;ll f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const ll MAXN=1e6+10;
    namespace zhangenming{
        struct node{
            ll y,next,v;
        }e[MAXN];
        ll linkk[MAXN],len=0,n,m,siz[MAXN]={},mm,f[2100][2100]={},tmp[2010]={};
        inline void insert(ll xx,ll yy,ll vv){
            e[++len].y=yy;e[len].next=linkk[xx];e[len].v=vv;linkk[xx]=len;
        }
        void init(){
            n=read();m=read();mm=n-m;
            for(ll i=1;i<n;i++){
                ll xx=read();ll yy=read();ll vv=read();
                insert(xx,yy,vv);insert(yy,xx,vv);
            }
        }
        inline void dp(ll st,ll father){
            siz[st]=1;
            for(ll i=linkk[st];i;i=e[i].next){
                if(e[i].y!=father){
                    dp(e[i].y,st);
                    memset(tmp,-1,sizeof(tmp));
                    for(ll j=0;j<=siz[st];j++){
                        for(ll k=0;k<=siz[e[i].y];k++){
                            tmp[j+k]=max(tmp[j+k],f[st][j]+f[e[i].y][k]+(m-k)*k*e[i].v+(siz[e[i].y]-k)*(mm-siz[e[i].y]+k)*e[i].v);
                        }
                    }
                    siz[st]+=siz[e[i].y];
                    for(int j=0;j<=siz[st];j++){
                        f[st][j]=tmp[j];
                    }
                }
            }
        }
    }
    int main(){
        using namespace zhangenming;
        init();
        dp(1,0);
        cout<<f[1][m]<<endl;
        return 0;
    }
    

      

  • 相关阅读:
    如何更好的发现问题
    【刷题 Python Tip】题目6~10
    No module named MYSQLdb 问题解决
    第一个python爬虫,爬取百度图片
    【刷题 Python Tip】题目1~5
    Python sql数据的增删改查简单操作
    一个简单的flask程序
    open函数
    句柄的创建
    内核对象
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/7885190.html
Copyright © 2020-2023  润新知