zoukankan      html  css  js  c++  java
  • [bzoj4033][HAOI2015]树上染色【dp】

    【题目描述】

    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

    【题解】

     树形dp,记f[i][j]表示在子树i中把j个点染成黑色,对整棵树产生的最大贡献,由于黑白点的总数是确定的,我们能轻易算出来,子树的根节点与它父亲的贡献。

    这样做看上去是O(n^3)的,但由于任意两个节点只会在lca计算相互的影响,总复杂度O(n^2)

    /* --------------
        user Vanisher
        problem bzoj-4033 
    ----------------*/
    # include <bits/stdc++.h>
    # define 	ll 		long long
    # define 	N 		2010
    using namespace std;
    ll g[N],f[N][N],size[N],head[N],place,n,k;
    struct node{
    	ll data,next,vote;
    }e[N*2];
    void build(ll u, ll v, ll w){
    	e[++place].data=v; e[place].next=head[u]; head[u]=place; e[place].vote=w;
    	e[++place].data=u; e[place].next=head[v]; head[v]=place; e[place].vote=w;
    }
    ll read(){
    	ll tmp=0, fh=1; char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    	return tmp*fh;
    }
    void dp(ll x, ll fa, ll w){
    	f[x][0]=0; f[x][1]=0; size[x]=1;
    	for (ll ed=head[x]; ed!=0; ed=e[ed].next){
    		if (e[ed].data==fa) continue;
    		dp(e[ed].data,x,e[ed].vote);
    		for (ll i=0; i<=size[x]+size[e[ed].data]; i++) g[i]=0;
    		for (ll i=0; i<=size[x]; i++)
    			for (ll j=0; j<=size[e[ed].data]; j++)
    				g[i+j]=max(g[i+j],f[x][i]+f[e[ed].data][j]);
    		for (ll i=0; i<=size[x]+size[e[ed].data]; i++) f[x][i]=g[i];
    		size[x]=size[x]+size[e[ed].data];
    	}
    	for (ll i=0; i<=k; i++)
    		f[x][i]=f[x][i]+((k-i)*i+(size[x]-i)*(n-size[x]-(k-i)))*w;
    }
    int main(){
    	n=read(), k=read();
    	for (ll i=1; i<n; i++){
    		ll u=read(),v=read(),k=read();
    		build(u,v,k);
    	}
    	dp(1,0,0);
    	printf("%lld
    ",f[1][k]);
    	return 0;
    }
    


  • 相关阅读:
    Hive 窗口函数LEAD LAG FIRST_VALUE LAST_VALUE
    xargs命令
    left semi join VS left join
    静态类静态属性静态方法
    DATASET()用法
    更改数据,ExecuteNonQuery()
    SqlDataReader
    数据适配器
    数据库连接-引用配置文件
    sql获取当前时间
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136033.html
Copyright © 2011-2022 走看看