[动态规划][树形dp]Bichrome Tree

题目描述

We have a tree with N vertices. Vertex 1 is the root of the tree, and the parent of Vertex i (2≤i≤N) is Vertex Pi.
To each vertex in the tree, Snuke will allocate a color, either black or white, and a non-negative integer weight.
Snuke has a favorite integer sequence, X1,X2,…,XN, so he wants to allocate colors and weights so that the following condition is satisfied for all v.
The total weight of the vertices with the same color as v among the vertices contained in the subtree whose root is v, is Xv.
Here, the subtree whose root is v is the tree consisting of Vertex v and all of its descendants.
Determine whether it is possible to allocate colors and weights in this way.

Constraints
1≤N≤1 000
1≤Pi≤i−1
0≤Xi≤5 000

输入

Input is given from Standard Input in the following format:
N
P2 P3 … PN
X1 X2 … XN

输出

If it is possible to allocate colors and weights to the vertices so that the condition is satisfied, print POSSIBLE; otherwise, print IMPOSSIBLE.

样例输入

3
1 1
4 3 2

样例输出

POSSIBLE

提示

For example, the following allocation satisfies the condition:
Set the color of Vertex 1 to white and its weight to 2.
Set the color of Vertex 2 to black and its weight to 3.
Set the color of Vertex 3 to white and its weight to 2.
There are also other possible allocations.

思路:就是,对每一个节点i,在子树(包括i)中和它同色的权值和固定了,此时,要使子树中和它异色的权值和越小越好,这样以便给在其上方的节点更多选择的余地,所以用状态dp[i],表示i节点的子树中和它异色的最小权值和是多少,其实也就是求i节点的子树(不包括i)中和它同色的不超过w[i]的最大权值和tmp,那么dp[i]=sum-tmp;

(其中sum=,j为i的直接子节点)

AC代码:

#include <iostream>
#include<cstdio>
#include<vector>
#define inf 0x3f3f3f3f
using namespace std;

vector<int> sons[1010];
int w[1010],dp[1010];
int tmp[1010][5050];
bool ok=true;

void dfs(int x){
  int sum=0;
  for(int i=0;i<(int)sons[x].size();i++) dfs(sons[x][i]);
  if(!ok) return;//在ok已经是false的状态下,不要再进行tmp的计算了,否则会导致sum爆int,引起一系列问题,比如RE
  for(int i=0;i<(int)sons[x].size();i++){
    int son=sons[x][i];
    sum+=(w[son]+dp[son]);
    for(int j=0;j<=w[x];j++){
        tmp[i+1][j]=-inf;        //tmp的状态转移方程
        if(j>=w[son]) tmp[i+1][j]=max(tmp[i+1][j],tmp[i][j-w[son]]+w[son]);
        if(j>=dp[son]) tmp[i+1][j]=max(tmp[i+1][j],tmp[i][j-dp[son]]+dp[son]);
    }
  }
  if(tmp[sons[x].size()][w[x]]<0) ok=false,dp[x]=inf;
  else dp[x]=sum-tmp[sons[x].size()][w[x]];
}

int main()
{
    int n;scanf("%d",&n);
    for(int i=2;i<=n;i++){
        int p;scanf("%d",&p);
        sons[p].push_back(i);
    }
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    dfs(1);
    if(ok) printf("POSSIBLE\n");
    else printf("IMPOSSIBLE\n");
    return 0;
}

原文地址:https://www.cnblogs.com/lllxq/p/9419226.html

时间: 2024-10-05 05:05:02

[动态规划][树形dp]Bichrome Tree的相关文章

CodeForces 109C 树形DP Lucky Tree

赶脚官方题解写得挺清楚的说,=_= 注意数据范围用long long,否则会溢出. 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 100000 + 10; 9 10 int n; 11 vecto

HDU 5379 树形DP Mahjong tree

任意一棵子树上节点的编号连续,每个节点的所有二字节点连续,求编号方案的总数. 稍微分析一下可知 每个节点的非叶子节点个数不能多于两个,否则这个子树无解,从而整棵树都无解. 每棵子树将所有节点按照编号从小到大排序,根节点要么在最左端,要么在最右端,而且这两种情况相等.(后面会有具体分析) 设size(u)表示以节点u为根的子树中节点总数. d(u)表示用1 ~ size(u)给以u为根的子树编号的合法方案数,考虑下面几种情况: ①:  u是叶子节点,方案数为1. ②:  u的所有儿子节点都是叶子节

动态规划(树形DP):HDU 5834 Magic boy Bi Luo with his excited tree

非常难想的树形DP. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int N=100010; 6 int cnt,fir[N],nxt[N*2],to[N*2],val[N*2]; 7 int n,w[N],ans[N],fa[N],f1[N][2],f2[N][2]; 8 void addedge(int a,int b,in

hdu5593--ZYB&#39;s Tree(树形dp)

问题描述 ZYB有一颗N个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,B,令fai??为节点i的父亲,fa?1??=0;fa?i??=(A∗i+B)%(i−1)+1,i∈[2,N] . 输出:输出时只需输出N个点的答案的xor和即可. 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 一行四个正整数N,K,A,

hdu 5379 Mahjong tree(树形dp)

题目链接:hdu 5379 Mahjong tree 树形dp,每个节点最多有2个子节点为一棵节点数大于1的子树的根节点,而且要么后代的节点值都大于,要么都小于本身(所以tson不为0是,要乘2).对于K个单一节点的子节点,种类数即为全排K!.当一个节点没有兄弟节点时,以这个节点为根结点的子树,根可以选择最大或者最小. #pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #inclu

hdu5293 Tree chain problem 树形dp+线段树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5293 在一棵树中,给出若干条链和链的权值.求选取不相交的链使得权值和最大. 比赛的时候以为是树链剖分就果断没去想,事实上是没思路. 看了题解,原来是树形dp.话说多校第一场树形dp还真多. . .. 维护d[i],表示以i为根节点的子树的最优答案. sum[i]表示i的儿子节点(仅仅能是儿子节点)的d值和. 那么答案就是d[root]. 怎样更新d值 d[i] = max(sum[i] , w[p]+s

树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

1 // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree 2 // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以走多次,问从每个点出发的最大获益 3 // 思路: 4 // dp[i]: 从i点出发回到i点的最大值 5 // d[i][0] 从i点出发不回来的最大值 6 // d[i][1] 从i点出发取最大值的下一个点 7 // d[i][2] 从i点出发取次大值 8 // dfs1处理出这四个 9

Bestcoder round #65 &amp;&amp; hdu 5593 ZYB&#39;s Tree 树形dp

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 354    Accepted Submission(s): 100 Problem Description ZYB has a tree with N nodes,now he wants you to solve the numbers of nodes distanced no m

codeforces161D - Distance in Tree 树形dp

题意:给你一棵树,问你树中距离为k的有多少种情况. 解题思路:树形dp  维护每个节点(1-K)深度的情况, 解题代码: 1 // File Name: 161d.cpp 2 // Author: darkdream 3 // Created Time: 2014年08月03日 星期日 19时20分10秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #incl