题目描述
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.
来源/分类
ABC074&ARC083
题意:每个结点可以染成黑色或白色,要求每个结点的子树中和自己同色的子结点的权值和加起来等于v[x],这里是包含自身的.
问你是否有一个可行的方案.
思路:这题看了网上很多博客大概明白的,这里就讲下我的理解每个结点可以染为黑色或白色,要求每个结点x要和他子树中所有同色结点的值的和相同,这里本身的值可以任意大,所以只要保证同色子结点的值小于等于他要求的v[x]就可以了.我们利用dfs,从下往上返值,那么假设一个结点已经被染成黑色,我们就得保证他的所有白色子结点能有最小值传递上去.同理若是白色,那就是有较小的黑色返上去.因为每个点肯定会有一个颜色,所以我们只要保证一个结点X在v[x]范围内可以可以通过所有子结点传递上来一个小的值就说明有可行的情况,然后在这基础上,找一个配色权值最小的情况即可.dp[i][j]表示考虑到第i个点,它子树的黑色权值和为j的情况下白色点权值和的最小值,并将dp初值设为inf。,当然这里的黑色白色不是绝对的,所以我们枚举每一个子结点配色情况就行.刚开始看不懂为什么他代码里有X=1-X,后来明白每一个子结点来判断的时候都会清一次dp[X],使得所有值变为iinf,这样可以在上一个结点的基础上进行DP操作,如果某个结点的v,mi都大于v[x],这样传递下去的所有值都是inf,也就没有解了,这样传上去也是INF,还是自己太蠢,理解了半天.
代码:
#include
using namespace std;
const int maxx=5005,maxn=1005,inf=0x3f3f3f3f;
int mi[maxn],dp[2][maxx];
int n;
int first[maxn],tot,v[maxn];
struct edg{
int v,from;
}e[maxn];
int read(){
char c;
int s=0,t=1;
while(!isdigit(c=getchar())) {
if(c=='-') t=-1;
}
do{
s=s*10+c-'0';
}while(isdigit(c=getchar()));
return s*t;
}
void insert(int u,int v){///建边
tot++;
e[tot].v=v;
e[tot].from=first[u];
first[u]=tot;
}
void dfs(int x){
for(int i=first[x];i;i=e[i].from) dfs(e[i].v);
memset(dp[0],0x3f,sizeof(dp[0]));
int X=0;
dp[X][0]=0;
for(int i=first[x];i;i=e[i].from){
int y=e[i].v;
X=1-X;
memset(dp[X],0x3f,sizeof(dp[X]));
for(int j=0;j<=v[x];j++){
if(j-v[y]>=0) dp[X][j]=min(dp[X][j],dp[1-X][j-v[y]]+mi[y]);
if(j-mi[y]>=0) dp[X][j]=min(dp[X][j],dp[1-X][j-mi[y]]+v[y]);
}
}
for(int i=0;i<=v[x];i++) mi[x]=min(mi[x],dp[X][i]);
}
int main(){
n=read();
for(int i=2;i<=n;i++){
int p=read();
insert(p,i);
}
for(int i=1;i<=n;i++) v[i]=read();
memset(mi,0x3f,sizeof(mi));
dfs(1);
if(mi[1]
}
参考博客:https://blog.csdn.net/Rising_shit/article/details/80849320 (讲的真好,可惜我还是看了半天).