arc 083 E Bichrome Tree

         题意: 给你一棵以1为根的树,让你将这棵树黑白染色,再给每个点赋一个权值,要求对于每个点,它和它子树中同样颜色的点权值之和要恰好等于x[v],问是否可行。 Miss U

         首先我们可以假设点 now 为黑色,如果是白色的话,我们后面的答案稍微换一下即可了。

         接着如果我们考虑一个点的子树的时候,如果已经知道了它的颜色(假如是黑色),我们只关心在该情况下白色的权值和最小值,而且只要某个点的子树黑色的权值和能达到一个小于等于x[now]的值说明这个状态合法。

         由于不关心在黑色的权值和确定的情况下,我们只关心白色的权值和最小值,那么我们就很容易得到一个dp状态了。dp[i][j]表示考虑到第i个点,它子树的黑色权值和为j的情况下白色点权值和的最小值,并将dp初值设为inf。

         考虑转移的时候,我们就可以分开讨论某个子节点 k 是黑色还是白色,

         如果子节点k是黑色,那么有dp[i][j+w[k]]=min(dp[i][j+w[k]],dp[i][j]+min(dp[k][0~w[k]]),即为给i的子树增加w[k]的黑色节点,为什么是min(dp[k][0~w[k]])呢,因为我并不需要k的子树里有w[k]个节点,只要有小于等于w[k]个,我给k这个节点增加差的权值就可以了。

         因为我们这时候只关心dp[k][0~w[k]]的最小值,预处理一下就可以了,我们令它为 x,

         同理,如果子节点k是白色,那么有dp[i][j+x]=min(dp[i][j+x],dp[i][j]+w[k]),由于黑色和白色是互逆的,所以这时候子节点k的dp的意义就变成了节点k染色为白色时,黑色的最小个数,便得到了如上的dp方程。

        这样从下向上dp,最后只要dp[1][0~w[1]]有一个dp值不为inf了,就说明有合法的转移能转移上来了,就说明有解,否则无解。

         注意treedp的时候防止一个子树多次更新dp值,可以每次先复制上一个子树的答案,再把dp数组置为inf再进行更新,(其实似乎反着枚举当背包就行了)

         下附AC代码。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#define maxn 1005
using namespace std;
int n,tot;
int head[maxn],nex[maxn],to[maxn],v[maxn];
void add(int x,int y)
{
	to[++tot]=y; nex[tot]=head[x]; head[x]=tot;
}
int dp[maxn][maxn*5],temp[maxn*5];
int dfs(int now)
{
	dp[now][0]=0;
	for(int i=head[now];i;i=nex[i])
	{
		int w=dfs(to[i]),b=v[to[i]];
 
		memcpy(temp,dp[now],sizeof(temp));
		memset(dp[now],0x3f,sizeof(dp[now]));
 
		for(int j=0;j<=v[now];j++)
		{
			if(j+w<=v[now])
				dp[now][j+w]=min(dp[now][j+w],temp[j]+b);
			if(j+b<=v[now])
				dp[now][j+b]=min(dp[now][j+b],temp[j]+w);
		}
 
	}
 
	int ans=dp[0][0];
 
	for(int i=0;i<=v[now];i++)
		ans=min(ans,dp[now][i]);
 
//	cerr<<now<<" "<<ans<<endl;
	return ans;
}
int main()
{
	memset(dp,0x3f,sizeof(dp));
 
	scanf("%d",&n);
	for(int i=2;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		add(x,i);
	}
	for(int i=1;i<=n;i++)
		scanf("%d",&v[i]);
	int res=dfs(1);
//	cout<<res<<endl;
	if(res<dp[0][0])
		return printf("POSSIBLE\n"),0;
	printf("IMPOSSIBLE\n");
}



我就想让某个傻子来试这里有没有彩蛋        Especially For U 

By ZRX


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值