[SDOI2006] 保安站岗

题目链接:https://www.luogu.org/problemnew/show/P2458

看到题目之后——果断树形DP啊!!

但是怎么树形DP啊qwq。。。。开始想的是(dp[i][0/1])来表示i节点选不选择。

那么状态转移方程:

(dp[i][0]=sum_{v=son(i)}^{}dp[v][1])

(dp[i][1]=val[i]+sum_{v=son(i)}min(dp[v][0],dp[v][1]))

然后如果所有小的都是dp[v][0],找一个最小的dp[v][1]加上,然后减去原先对应加上的。

但是!!这样的写法不对!!

会被这样一组简单的数据hack掉:

9
1 1 1 2
2 5 3 3 4 5
3 100 1 6
4 100 1 7
5 100 2 8 9
6 1 0
7 1 0
8 1 0
9 1 0

为什么呢?是因为我们没有考虑用父亲节点控制该节点的情况

所以正确的状态设计应该是这样的:

(dp[i][0])表示节点(i)至少被父亲节点控制。

(dp[i][1])表示节点(i)至少被子节点控制。

(dp[i][2])表示节点(i)至少被自己控制。

那么正确的状态转移方程是:

(dp[i][0]=sum min(dp[son(i)][1],dp[son(i)][2]))

(dp[i][1]=sum min(dp[son(i)][1],dp[son(i)][2])+dp[son(i)][2])
(其中至少有一个是1)

(dp[i][2]=sum min(dp[son(i)][0],dp[son(i)][1],dp[son(i)][2])+val[i])

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 2010
using namespace std;
struct Edge{int nxt,to;}edge[MAXN<<1];
int edge_number,n,ans=2147483647;
int val[MAXN],head[MAXN];
long long dp[MAXN][3];
void add(int from,int to)
{
    edge[++edge_number].nxt=head[from];
    edge[edge_number].to=to;
    head[from]=edge_number;
}
inline void search(int now,int fa)
{
    long long sum=0;
    dp[now][2]=val[now];
    for(int i=head[now];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==fa) continue;
        search(v,now);
        dp[now][2]+=min(dp[v][2],min(dp[v][1],dp[v][0]));
        sum+=min(dp[v][1],dp[v][2]);
    }
    dp[now][0]=sum;
    dp[now][1]=2147483647;
    for(int i=head[now];i;i=edge[i].nxt)
    {
    	int v=edge[i].to;
    	if(v==fa) continue;
		dp[now][1]=min(dp[now][1],sum+dp[v][2]-min(dp[v][1],dp[v][2]));
	}
    return;
}
int main()
{
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int u,w,sum;
        scanf("%d%d%d",&u,&w,&sum);
        val[u]=w;
        for(int j=1;j<=sum;j++)
        {
            int v;
            scanf("%d",&v);
            add(u,v);
            add(v,u);
        }
    }
    memset(dp,0x3f,sizeof(dp));
    search(1,0);
    printf("%lld
",min(dp[1][1],dp[1][2]));
    return 0;
}
原文地址:https://www.cnblogs.com/fengxunling/p/9849108.html