• 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) 值。

  • 相关阅读:
    python之RabbitMQ
    RHEL 使用epel源
    Python操作 Memcache
    LOJ #6053. 简单的函数 (min25筛裸题)
    [51Nod
    Min25筛学习 + 【51nod1847】奇怪的数学题(Min_25筛+杜教筛)
    BZOJ 3331: [BeiJing2013]压力 (点双 圆方树 树链剖分 线段树)
    BZOJ 2125: 最短路(仙人掌 圆方树)
    模拟赛题解 naive (二分)
    BZOJ 2286 [Sdoi2011]消耗战 (虚树模板题)
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11369302.html
Copyright © 2020-2023  润新知