zoukankan      html  css  js  c++  java
  • Codeforces 1153D 树形DP

    题意:有一个游戏,规则如下:每个点有一个标号,为max或min, max是指这个点的值是所有子节点中值最大的那一个,min同理。问如何给这颗树的叶子节点赋值,可以让这棵树的根节点值最大。

    思路:很明显的树形dp, 设dp[x]是指以x为根的子树中可以获得的最大的值, sz[x]是指以x为根的子树中叶子节点的个数。

    若x是max, 那么dp[x] = max(sz[x] - sz[y] + dp[y]),对应的决策相当于把最大的几个值给dp[y] - sz[y]最大的那颗子树。

    若x是min, 首先需要统计每颗子树的sz[y] - dp[y], 这些都不可能被选上了,之后,还要统计有多少棵子树(假设有z棵), 其中z - 1个肯定选不上了,所以答案是sz[x] - Σ(sz[y] - dp[y]) - (z - 1)。

    这两条对照这样例的图很容易就能发现了,然而昨晚思路跑偏了,这题都没做出来,含泪掉分。。。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 300010;
    vector<int> G[maxn];
    int sz[maxn], dp[maxn], a[maxn];
    void dfs(int x) {
    	dp[x] = 1;
    	if(G[x].size() == 0) {
    		sz[x] = 1;
    		return; 
    	}
    	for (int i = 0; i < G[x].size(); i++) {
    		int y = G[x][i];
    		dfs(y);
    		sz[x] += sz[y];
    	}
    	if(a[x] == 1) {
    		for (int i = 0; i < G[x].size(); i++) {
    			int y = G[x][i];
    			dp[x] = max(dp[x], sz[x] - sz[y] + dp[y]);
    		}
    	} else {
    		int tmp = 0;
    		for (int i = 0; i < G[x].size(); i++) {
    			int y = G[x][i];
    			tmp += sz[y] - dp[y];
    		}
    		dp[x] = sz[x] - tmp - G[x].size() + 1;
    	}
    }
    int main() {
    	int n, x;
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d", &a[i]);
    	}
    	for (int i = 2; i <= n; i++) {
    		scanf("%d", &x);
    		G[x].push_back(i);
    	}
    	dfs(1);
    	printf("%d
    ", dp[1]);
    } 
    

      

  • 相关阅读:
    关于Spring和Struts2的整合
    有关Transaction not successfully started问题解决办法
    两种页面跳转
    jdbc连接mysql
    change和modify
    Navicat Premium 15连接Oracle时提示oracle library is not loaded的解决方案
    Oracle创建本地数据库实例及配置监听
    下载Visual Studio 2019离线安装包
    简单的数据库
    未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10704633.html
Copyright © 2011-2022 走看看