SSL_1608&&ybtoj【动态规划】4章2题【结点覆盖】

结点覆盖

题目


解析

一个节点被覆盖只有三种可能: 设 d p x , 0 / 1 / 2 设dp_{x,0/1/2} dpx,0/1/2分别表示被孩子/自己/父亲覆盖,可以得到转移方程:
d p x , 0 = m i n ( d p s o n x , 1 − m i n ( d p s o n x , 1 , d p s o n x , 0 ) ) + ∑ m i n ( d p s o n x , 0 , d p s o n x , 1 ) dp_{x,0}=min(dp_{son_x,1}-min(dp_{son_x,1},dp_{son_x,0}))+∑min(dp_{son_x,0},dp_{son_x,1}) dpx,0=min(dpsonx,1min(dpsonx,1,dpsonx,0))+min(dpsonx,0,dpsonx,1)
(选一个1,其余选min(0,1))
d p x , 1 = w x + ∑ m i n ( d p s o n x , 0 , d p s o n x , 1 , d p s o n x , 2 ) dp_{x,1}=w_x+∑min(dp_{son_x,0},dp_{son_x,1},dp_{son_x,2}) dpx,1=wx+min(dpsonx,0,dpsonx,1,dpsonx,2)
(子节点随便选)
d p x , 2 = ∑ d p s o n x , 0 dp_{x,2}=∑dp_{son_x,0} dpx,2=dpsonx,0
(显然它的父节点,它本身及它的子节点都没有选,故子节点只有0的状态)
最终答案即为 m i n ( d p x , 0 , d p x , 1 ) min(dp_{x,0},dp_{x,1}) min(dpx,0,dpx,1)(因为根没有父节点)

code:

#include<cstdio>
#define int long long
using namespace std;
inline int min(int x,int y){return x<y?x:y;}
int n,x,y,q,nxt[3010],to[3010],tot,head[1510],dp[1510][3],val[1510];
inline void add(int x,int y){to[++tot]=y,nxt[tot]=head[x],head[x]=tot;}
inline void dfs(int x,int fa)
{
	register int mn=0;
	dp[x][1]=val[x],dp[x][0]=1e9;
	for(int i=head[x];i;i=nxt[i])if(to[i]!=fa)dfs(to[i],x),mn+=min(dp[to[i]][0],dp[to[i]][1]),dp[x][1]+=min(min(dp[to[i]][1],dp[to[i]][0]),dp[to[i]][2]),dp[x][2]+=dp[to[i]][0];
	for(int i=head[x];i;i=nxt[i])if(to[i]!=fa)dp[x][0]=min(dp[x][0],mn-min(dp[to[i]][0],dp[to[i]][1])+dp[to[i]][1]);
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&x),scanf("%lld%lld",&val[x],&q);
		while(q--)scanf("%lld",&y),add(x,y),add(y,x);
	}
	dfs(1,0);
	printf("%lld",min(dp[1][0],dp[1][1]));
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值