zoukankan      html  css  js  c++  java
  • 洛谷P3177 树上染色

    题意:

    给n,K,n个点的树,K个点是黑色的,n-k点是白色的

    给n-1条u,v,w,收益值是黑点两两距离之和,和白点两两距离之和的总值

    求最大的收益值

    思路:

    因为是树形的,所以想到了求dp,dp[u][i] 求u为根的选有多少i个黑点的收益值,然后卡壳

    翻了题解,发现dp[u][i] 求得是以u为根的 i 个黑点的贡献值,就是有一个通式:这条边左边的黑点*这条边右边的黑点*w+这条边左边的白色*这条边右边的白点*w

    突然就豁然开朗了,仔细想想,我应该……应该个p   笨脑子不可能想到算贡献的,告辞。这个通式如果是自己想到推出来,可能会吹一辈子

    接下来就是在树里面进行dp了

    f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+val);

    val就是那个通式:

    这条边左边黑点数:k

    这条边右边黑点数:K-k

    这条边左边白点数:sz[v]-k,sz[v]是以u为根连接着 v 点的子树点数

    这条边右边的白点数:n-K-(sz[v]-k)

    接下来就是类似01背包操作吧

    写得过程各种wa,tle,参考了别人ac代码,修修改改终于ac了

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define il inline
    #define it register int
    #define inf 0x3f3f3f3f
    #define lowbit(x) (x)&(-x)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define mod 1000000007
    const int maxn=2010;
    struct node{
        int to,next;
        ll w;
    }a[maxn<<1];
    int n,k1,cnt,tot,head[maxn];
    ll f[maxn][maxn];
    int sz[maxn]={0};
    il void add(int u,int v,ll w){
        a[tot].w=w;a[tot].next=head[u];
        a[tot].to=v;head[u]=tot++;
    }
    void dfs(int u,int qian){
        sz[u]=1;f[u][0]=f[u][1]=0;
        for(it i=head[u];i!=-1;i=a[i].next){
            int v=a[i].to;
            if(v==qian){continue;}
            dfs(v,u);
            sz[u]+=sz[v];
        }
         for(it i=head[u];i!=-1;i=a[i].next){
            int v=a[i].to;
            if(v==qian){continue;}
            for(it j=min(sz[u],k1);j>=0;j--){
                for(it k=0;k<=min(j,sz[v]);k++){
                    if(f[u][j-k]>=0){
                        ll val=(ll)k*(k1-k)*a[i].w+(ll)(sz[v]-k)*(n-k1-sz[v]+k)*a[i].w;
                        //cout<<val<<" "<<j<<" "<<k<<endl;
                        f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+val);
                    }
                }
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&k1);
        tot=0;mem(head,-1);mem(f,-inf);
        for(it i=1;i<n;i++){
            int u,v;
            ll w;
            scanf("%d%d%lld",&u,&v,&w);
            add(u,v,w);add(v,u,w);
        }
        dfs(1,-1);
      //cout<<sz[1]<<endl;
        printf("%lld
    ",f[1][k1]);
        return 0;
    }
    /*
    4 1
    1 2 1
    1 3 1
    1 4 1
    
    6
    */

    ……希望在这条路上多坚持坚持

  • 相关阅读:
    jquery 读取 xml 属性等于某值的 方法
    jquery 定时器
    jquery div 滚动条 最底部
    ajax success 不能返回值解决方案 async:false
    wiki 使用说明
    thinkphp 二维码封装函数
    100本书 慢慢来读
    2013 来了
    jquery 解析 xml
    键盘按键 事件
  • 原文地址:https://www.cnblogs.com/luoyugongxi/p/12267113.html
Copyright © 2011-2022 走看看