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

    (Link)

    Description

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

    Solution

    妙妙的树形(DP)

    我们设(dp[x][t])表示在以(x)为根的子树中选择(t)个点染黑时的最大贡献。

    发现距离不太好搞,那么我们可以将距离转化为路径,然后再将路径拆分成边,就可以记录每条边被经过的次数,直接计算即可。

    我们枚举(x)的子节点(y),先处理(y)这棵子树和其他子树,再对(x)做贡献。分别枚举(y)中被染黑的节点数(tn)(x)中除了(y)的子树被染黑的节点数(te)。注意要倒序枚举,避免后效性。那么这样产生的贡献就是(value=z*(k - tn) * tn + (sz[y] - tn) * (n - k - sz[y] + tn))(黑点贡献加上白点贡献)。

    总的方程就是(dp[x][te+tn]=max{dp[x][te]+dp[y][tn]+value})

    注意枚举(sz[])的时候,不要在最开始就一遍算出来,要一边算,一遍处理(DP)数组。这样就不会重复算,防止超时。因为(x)可能会有多棵子树,我们一棵一棵枚举,现在的(dp[x][te])其实就是之前的(dp[x][te+tn]),正好已经算过。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    
    int n, k, tot, hd[2005], to[4005], nxt[4005], w[4005], sz[2005];
    
    ll dp[2005][2005];
    
    int read()
    {
    	int x = 0, fl = 1; char ch = getchar();
    	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    	return x * fl;
    }
    
    void add(int x, int y, int z)
    {
    	tot ++ ;
    	to[tot] = y;
    	w[tot] = z;
    	nxt[tot] = hd[x];
    	hd[x] = tot;
    	return;
    }
    
    void dfs(int x, int fa)
    {
    	sz[x] = 1;
    	for (int i = hd[x]; i; i = nxt[i])
    	{
    		int y = to[i], z = w[i];
    		if (y == fa) continue;
    		dfs(y, x);
    		sz[x] += sz[y];
    		for (int te = sz[x] - sz[y]; te >= 0; -- te) // 注意是倒序枚举!
    			for (int tn = sz[y]; tn >= 0; -- tn)
    				dp[x][te + tn] = max(dp[x][te + tn], dp[x][te] + dp[y][tn] + 1ll * z * ((k - tn) * tn + (sz[y] - tn) * (n - k - sz[y] + tn)));
    	}
    	return;
    }
    
    int main()
    {
    	n = read(); k = read();
    	for (int i = 1; i <= n - 1; i ++ )
    	{
    		int x = read(), y = read(), z = read();
    		add(x, y, z); add(y, x, z);
    	}
    	dfs(1, 0);
    	printf("%lld
    ", dp[1][k]);
    	return 0;
    }
    
  • 相关阅读:
    DMA
    [计网笔记] 应用层
    为博客添加网易云音乐播放器外链
    acm对拍程序 以及sublime text3的文件自动更新插件auto refresh
    操作系统---内存管理(上) 概念 覆盖交换技术 连续分配管理方式
    操作系统---死锁的检测和解除
    C++ bitset的使用
    Codeforces Round #647 (Div. 2)
    sublime Text3 实现2:1:1三分屏效果
    操作系统---信号量以及四个进程同步问题
  • 原文地址:https://www.cnblogs.com/andysj/p/13906877.html
Copyright © 2011-2022 走看看