• LuoGuP3177:[HAOI2015]树上染色


    Pre

    想不出来,不得不说这套路还不错。

    调试代码到了最后发现有一个地方 (u) 写成了 (to[i])

    Solution

    考虑每一条边的贡献。

    (w=w_i*cntblack_{left}*cntblack_{right}+w_i*cntwhite_{left}*cntwhite_{right})

    以这个等式进行 (DP)

    最终计算答案。

    Code

    #include <cstdio>
    #include <cstring>
    #include <limits.h>
    #define ll long long
    using namespace std;
    inline ll min (ll u, ll v) { return u > v ? v : u;}
    inline ll max (ll u, ll v) { return u > v ? u : v;}
    const int N = 2000 + 5;
    int n, k;
    int fr[N << 1], to[N << 1], h[N], tot, sz[N];
    ll val[N << 1], dp[N][N];
    inline void dfs (int u, int f) {
    	memset (dp[u], -1, sizeof dp[u]);
    	dp[u][0] = dp[u][1] = 0;
    	sz[u] = 1;
    	for (int i = h[u]; i; i = fr[i]) {
    		if (to[i] == f) continue;
    		dfs (to[i], u);
    		sz[u] += sz[to[i]];
    	}
    	for (int i = h[u]; i; i = fr[i]) {
    		if (to[i] == f) continue;
    		for (int c = min (k, sz[u]); c >= 0; --c) {
    			for (int j = 0; j <= min (c, sz[to[i]]); ++j) {
    				if (~dp[u][c - j])
    					dp[u][c] = max (dp[u][c], dp[u][c - j] + dp[to[i]][j] + val[i] * j * (k - j) + val[i] * (sz[to[i]] - j) * (n - k + j - sz[to[i]]));
    			}
    		}
    	}
    }
    inline void add (int u, int v, ll w) {
    	tot++;
    	fr[tot] = h[u];
    	to[tot] = v;
    	h[u] = tot;
    	val[tot] = w;
    }
    int main () {
    	#ifdef chitongz
    	freopen ("x.in", "r", stdin);
    	#endif
    	scanf ("%d%d", &n, &k);
    	for (int i = 1; i < n; ++i) {
    		int x, y; ll z;
    		scanf ("%d%d%lld", &x, &y, &z);
    		add (x, y, z); add (y, x, z);
    	}
    	dfs (1, 0);
    	printf ("%lld
    ", dp[1][k]);
    	return 0;
    }
    

    Conclusion

    尝试换一个方向思考。

    Update

    有人询问代码中

    if (~dp[u][c - j])
    

    的作用。

    也就是为什么没有初始化的点不能使用,可能想到 (-1) 不会对答案造成贡献。

    但是假设根节点 (rt) 有子树 (p_1,p_2,cdots) ,并且按顺序更新。

    由于是先把 (sz[u]) 求出来再进行更新,所以在更新这个子树的时候,前面的子树的大小是严格小于 (sz[u]) 的,而转移当中取得 (c)(min(k,sz[u])) ,也就是可以取到 (sz[u]) ,而一旦取到就会出现我想要在原来的子树安排的黑色节点数量大于它的数量上限,也就是(sz[p_1]+sz[p_2]+cdots)。这种情况下由于我的白色节点个数较多,答案可能更优,甚至远大于 (-1) ,所以依然会更新根节点的 (DP) 值。也就是出现了,比如,某一个大小为 (5) 的子树,有两个子树,大小分别为 (1,3) ,某一个 (DP) 值要求在这个大小为 (5) 的子树安排下 (3) 个黑色节点,表面上看是可行的,但是 (DP) 的结果却是在大小为 (1) 的子树安排 (2) 个黑色节点,在另一个子树安排 (1) 个黑色节点,这样才能达到 (rt) 节点的最优。但是这样是不可能的,其原因就在于大小为 (3) 的子树在更新答案的使用非法使用了前面的子树的 (DP) 值,也就是 (dp[rt][2]) ,安排 (2) 个黑色节点的 (DP) 值。

  • 相关阅读:
    用js实现 全选功能(Gridview)
    图片 加文字水印或者图片水印
    Gridview中RowCommand事件的应用
    图片噪点的产生
    DataList实现折叠效果
    利用Request对象的CurrentExecutionFilePath做分页
    利用分页控件AspNetPager来做数据的分页
    log4Net一些记忆性总结
    彩色验证码
    组织机构设计器窗体基类 代码分析
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11369302.html
Copyright © 2020-2023  润新知