• 【BZOJ】4033: [HAOI2015]树上染色 树上背包


    【题目】#2124. 「HAOI2015」树上染色

    【题意】给定n个点的带边权树,要求将k个点染成黑色,使得 [ 黑点的两两距离和+白点的两两距离和 ] 最大。n<=2000。

    【算法】树上背包

    【题解】设f[i][j]表示子树i中有j个黑点对答案的贡献(包括点 i 到父亲的边 p ),由于边p的贡献只和 j 有关,所以最后再统计。

    所以做树上背包即可,注意这题特殊在f[x][0]≠0,所以初始f[x][k]+=f[y][0],然后不要把0作为物品。

    最后统计边p的贡献:w[p] *(子树内黑点*子树外黑点+子树内白点*子树外白点)。

    常数问题:要尽可能避免枚举无用状态,不然常数太大了,优化见代码。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn=2010,inf=0x3f3f3f3f;
    struct edge{int v,w,from;}e[maxn*2];
    int first[maxn],tot,n,K,sz[maxn];
    ll f[maxn][maxn];
    void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
    ll max(ll a,ll b){return a<b?b:a;}
    void dfs(int x,int fa,int w){
        for(int i=2;i<=K;i++)f[x][i]=-inf;
        sz[x]=1;
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
            dfs(e[i].v,x,e[i].w);
            sz[x]+=sz[e[i].v];
            for(int k=min(sz[x],K);k>=0;k--){
                f[x][k]+=f[e[i].v][0];//
                for(int j=min(k,sz[e[i].v]);j>=1;j--)if(f[x][k-j]>-inf){//
                    f[x][k]=max(f[x][k],f[x][k-j]+f[e[i].v][j]);
                }else break;
            }
        }
        for(int i=0;i<=K;i++)if(f[x][i]>-inf)f[x][i]+=1ll*w*(1ll*i*(K-i)+1ll*(sz[x]-i)*(n-K-sz[x]+i));
    }
    int main(){
        scanf("%d%d",&n,&K);
        for(int i=1;i<n;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            insert(u,v,w);insert(v,u,w);
        }
        dfs(1,0,0);
        printf("%lld",f[1][K]);
        return 0;
    }
    View Code
  • 相关阅读:
    Asp.net获取客户端的IP地址排除::1
    EF 筛选列包含NULL会报错
    layUI关于table编辑列支持方向键功能
    .NET CORE 发布IIS问题收集
    VS2019最新源代码管理工具+附下载地址
    关于Mysql可视化工具Navicat Premium12激活使用【亲测】
    经典SQL 语句
    事务的四种隔离级别 [转载]
    HTML 特殊符号编码对照表
    github本地文件Push到仓库
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8553588.html
Copyright © 2020-2023  润新知