LOJ10157——皇宫看守(树形DP)

传送门:QAQQAQ

 

题意:在一个树上放置守卫,使每一个节点都至少有相邻一节点放置守卫,使最终经费最少

 

思路:树形DP

首先会想到没有上司的舞会,0表示不放守卫,1表示放守卫,但考虑到对于当前点不放守卫会有两种情况:

1.其父亲放守卫,则其儿子没必要放守卫

2.其父亲没放守卫,则其儿子必须至少有一个放守卫

所以思路就很明显了:dp1表示当前点放守卫,dp0表示当前点没守卫,其父亲有守卫,dp2表示当前没守卫,父亲没守卫,然后进行递推即可

读入时点可能是不按照顺序的,这点需要注意。

 

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=1020+500;
const ll inf=2000000000;

ll n,w[N],dp[N][3];//0:father1now0 1:now1 2:father0now0
vector<ll> v[N];

ll checkmin(ll x,ll y,ll z)
{
    return min(min(x,y),z);
}

void dfs(ll u,ll f)
{
    ll bl=0,minn=inf;
    for(ll i=0;i<(ll)v[u].size();i++)
    {
        ll p=v[u][i];
        if(p==f) continue;
        dfs(p,u); 
        dp[u][1]+=min(dp[p][1],dp[p][0]);
        dp[u][0]+=min(dp[p][2],dp[p][1]);
        if(dp[p][1]<=dp[p][2])
        {
            bl=1;
            dp[u][2]+=dp[p][1];
        }
        else
        {
            dp[u][2]+=dp[p][2];
            minn=min(minn,dp[p][1]-dp[p][2]);
        }
    }
    dp[u][1]+=w[u];
    if(!bl) dp[u][2]+=minn;
}

int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        ll tmp,m;
        scanf("%lld",&tmp);
        scanf("%lld%lld",&w[tmp],&m);
        for(ll j=1;j<=m;j++)
        { 
            ll x;
            scanf("%lld",&x); 
            v[tmp].push_back(x);
            v[x].push_back(tmp);
        }
    }
    memset(dp,0,sizeof(dp));
    dfs(1,-1);
    printf("%lld",min(dp[1][1],dp[1][2]));
    return 0;
}
View Code

 

posted @ 2019-07-23 22:35  'Clovers'  阅读(319)  评论(0编辑  收藏  举报