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

    嘟嘟嘟


    首先这一眼看出来,要树形dp。
    然后发现状态不好设,刚开始我想的是dp[i][j]表示以(i)为根的子树,选了(j)个黑点的最大价值。结果就不会转移了。
    转移的时候想考虑(<u, v, w>)这一条边的贡献,但是发现这个状态的转移所涉及的不只是这一条边,还有子树中的边,于是就彻底gg了。
    还是看了题解。
    题解也是考虑贡献,而且也是考虑每一条边,但最大的区别是,我们枚举边,然后考虑边两侧的点对答案的贡献。
    令dp[i][j]表示以(i)为根的子树,选了(j)个黑点,已经枚举到第(x)条边时,当前答案的最大值。
    因为dfs的时候就相当于枚举边了,所以这一维自然省去。
    于是对于黑点,有(j * (K - j) * w(u, v))的贡献,
    对于白点,有((K - j) * (n - size[v] - (K - j)) * w(u, v))的贡献。
    最后记得要初始化dp数组为-INF,因为有些状态不合法。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 2e3 + 5;
    inline ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), last = ' ';
    	while(!isdigit(ch)) {last = ch; ch = getchar();}
    	while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
    	if(last == '-') ans = -ans;
    	return ans;
    }
    inline void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n, K;
    struct Edge
    {
    	int nxt, to; ll w;
    }e[maxn << 1];
    int head[maxn], ecnt = -1;
    In void addEdge(int x, int y, ll w)
    {
    	e[++ecnt] = (Edge){head[x], y, w};
    	head[x] = ecnt;
    }
    
    int siz[maxn];
    ll dp[maxn][maxn];
    In void dfs(int now, int _f)
    {
    	siz[now] = 1; dp[now][0] = dp[now][1] = 0;
    	for(int i = head[now], v; i != -1; i = e[i].nxt)
    	{
    		if((v = e[i].to) == _f) continue;
    		dfs(v, now);
    		siz[now] += siz[v];
    		for(int j = min(siz[now], K); j >= 0; --j)
    			for(int k = 0; k <= min(j, siz[v]); ++k)
    				dp[now][j] = max(dp[now][j], dp[now][j - k] + dp[v][k] + 1LL * k * (K - k) * e[i].w + 1LL * (siz[v] - k) * (n - siz[v] - K + k) * e[i].w);
    	}
    }
    
    int main()
    {
    	Mem(head, -1);
    	n = read(); K = read();
    	for(int i = 1; i < n; ++i)
    	{
    		int x = read(), y = read(); ll w = read();
    		addEdge(x, y, w); addEdge(y, x, w);
    	}
    	for(int i = 1; i <= n; ++i) fill(dp[i] + 1, dp[i] + K + 1, INF);
    	//带劲的操作 
    	dfs(1, 0);
    	write(dp[1][K]), enter;
    	return 0;
    }
    
  • 相关阅读:
    容器平台选型的十大模式:Docker、DC/OS、K8S 谁与当先?
    Spring Controller里注入Feign的Interface报红提示的问题
    几种常见的日志
    个人博客搭建方案选择
    elasticsearch常用操作命令
    kafka操作命令
    centos7.0安装java环境
    CentOS安装jdk的三种方法
    在OAuth2中 自定义tokenServices来提供个性化服务,每次刷新token并让原token在5分钟内有效
    解决HttpServletRequest的输入流只能读取一次的问题(转)
  • 原文地址:https://www.cnblogs.com/mrclr/p/10209710.html
Copyright © 2011-2022 走看看