洛谷P2458 [SDOI2006]保安站岗 题解(树上dp,巧妙,动态规划,较难)

solution:

d p [ u ] [ 0   2 ] dp[u][0~2] dp[u][0 2]

0 : 点 u 处 站 了 一 个 保 安 0:点u处站了一个保安 0:u

d p [ u ] [ 0 ] = a [ u ] dp[u][0]=a[u] dp[u][0]=a[u]
d p [ u ] [ 0 ] + = m i n ( d p [ v ] [ 0   2 ] ) dp[u][0]+=min(dp[v][0~2]) dp[u][0]+=min(dp[v][0 2])

2 : 点 u 处 没 有 站 保 安 , 点 u 靠 父 亲 来 安 保 2:点u处没有站保安,点u靠父亲来安保 2:uu
d p [ u ] [ 2 ] + = m i n ( d p [ v ] [ 0   1 ] ) dp[u][2]+=min(dp[v][0~1]) dp[u][2]+=min(dp[v][0 1])

1 : 点 u 处 没 有 站 保 安 , 点 u 靠 某 个 儿 子 来 安 保 1:点u处没有站保安,点u靠某个儿子来安保 1:uu
d p [ u ] [ 1 ] + = m i n ( d p [ v ] [ 0   1 ] ) dp[u][1]+=min(dp[v][0~1]) dp[u][1]+=min(dp[v][0 1])
在 计 算 的 时 候 顺 便 看 一 下 在计算的时候顺便看一下 便
如 果 d p [ u ] [ 1 ] = = s i g m a d p [ v ] [ 1 ] 如果dp[u][1]==sigma dp[v][1] dp[u][1]==sigmadp[v][1]
找 一 个 最 小 的 d p [ v ] [ 0 ] − d p [ v ] [ 1 ] 找一个最小的dp[v][0]-dp[v][1] dp[v][0]dp[v][1]
d p [ u ] [ 1 ] + = d p [ v ] [ 0 ] − d p [ v ] [ 1 ] dp[u][1]+=dp[v][0]-dp[v][1] dp[u][1]+=dp[v][0]dp[v][1]

答 案 : m i n ( d p [ r o o t ] [ 0 ] , d p [ r o o t ] [ 1 ] ) 答案:min(dp[root][0], dp[root][1]) :min(dp[root][0],dp[root][1])

code:

/*
dp[u][0~2]

0:点u处站了一个保安

dp[u][0]=a[u]
dp[u][0]+=min(dp[v][0~2])

2:点u处没有站保安,点u靠父亲来安保
dp[u][2]+=min(dp[v][0~1])

1:点u处没有站保安,点u靠某个儿子来安保
dp[u][1]+=min(dp[v][0~1])
在计算的时候顺便看一下
如果dp[u][1]==sigma dp[v][1]
找一个最小的dp[v][0]-dp[v][1]
dp[u][1]+=dp[v][0]-dp[v][1]

答案:min(dp[root][0], dp[root][1])
*/ 

#include<cstdio>
#include<vector>
#include<algorithm> 
using namespace std;
int f[1505][5];
int val[1505];
vector<int>e[1505];
void TreeDp(int x,int fa)
{
	f[x][0]=val[x];
	int tag=0;
	int ls=1000000007;
	for(int i=0;i<e[x].size();i++)
	{
	
		int y=e[x][i];
		if(y==fa)continue;
		TreeDp(y,x);
		int tmp=min(f[y][0],f[y][1]);
		f[x][0]+=min(tmp,f[y][2]);
		f[x][2]+=tmp;
		if(f[y][0]<f[y][1])tag++;
		else
		{
			ls=min(ls,f[y][0]-f[y][1]);
		}
		f[x][1]+=tmp;
	}
	if(tag==0)
	{
		f[x][1]+=ls; 
	}
	return ;
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int num,m,x;
		scanf("%d",&num);
		scanf("%d",&val[num]);
		scanf("%d",&m);
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&x);
			e[num].push_back(x);
			e[x].push_back(num);
		}
	}
	TreeDp(1,0);
	printf("%d\n",min(f[1][0],f[1][1]));
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShineEternal

觉得好就给点鼓励呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值