保安站岗 洛谷 - P2458

https://www.luogu.org/problemnew/show/P2458

一开始想当然用两种状态dp[i][0]代表i不站人 dp[i][1]代表i站人。。 这样每隔一层必站一个人 肯定不对 当u的儿子v站人后 只通过两种状态不能完全体现v对u的监视作用 即u的父亲f不知道u是否还需要保护 只要u不站人就会觉得u需要保护 从而无法做出正确决定

比如下面这个样例

4
1 1 1 2
2 2 1 3
3 2 1 4
4 1 0

dp[i][0]代表i无人监视 dp[i][1]代表i被人监视 dp[i][2]代表i站人 这才是完整状态 解决了上述问题

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=0x3f3f3f3f;
const int maxn=2e3+10;

vector <int> edge[maxn];
int dp[maxn][3];
int val[maxn],book[maxn],pre[maxn],suf[maxn];
int n,root;

void dfs(int cur)
{
    int i,v,flag,sum;
    dp[cur][0]=0;//1
    dp[cur][1]=N;//12
    dp[cur][2]=val[cur];//012
    for(i=0;i<edge[cur].size();i++){
        v=edge[cur][i];
        dfs(v);
    }

    flag=1;
    for(i=0;i<edge[cur].size();i++){
        v=edge[cur][i];
        dp[cur][0]+=dp[v][1];
        if(dp[v][1]==N) flag=0;
    }
    if(!flag) dp[cur][0]=N;

    sum=0;
    for(i=0;i<edge[cur].size();i++){
        v=edge[cur][i];
        sum+=min(dp[v][1],dp[v][2]);
    }
    for(i=0;i<edge[cur].size();i++){
        v=edge[cur][i];
        dp[cur][1]=min(dp[cur][1],sum-min(dp[v][1],dp[v][2])+dp[v][2]);
    }

    for(i=0;i<edge[cur].size();i++){
        v=edge[cur][i];
        dp[cur][2]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
    }
    //printf("*%d %d %d %d*\n",cur,dp[cur][0],dp[cur][1],dp[cur][2]);
}

int main()
{
    int i,k,u,v;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d",&u);
        scanf("%d",&val[u]);
        scanf("%d",&k);
        while(k--){
            scanf("%d",&v);
            edge[u].pb(v);
            book[v]=1;
        }
    }
    for(i=1;i<=n;i++){
        if(!book[i]) root=i;
    }
    dfs(root);
    printf("%d\n",min(dp[root][1],dp[root][2]));
    return 0;
}

/*
3
1 1 2 2 3
2 1000 0
3 1000 0
*/

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/89785427