HDU 1054 Strategic Game

树形DP。

dp[i][1]表示 在编号为 i 的节点上放置一个人,覆盖 编号为 i 的节点 的子树上所有边 需要的数量。

dp[i][0]表示 在编号为 i 的节点上不放置人,覆盖 编号为 i 的节点 的子树上所有边 需要的数量。

也可以用二分图匹配来做,在数量上,二分图的最小点覆盖数=二分图的最大匹配。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn=1500+10;
int n;
int dp[maxn][3];
int tot[maxn];
vector<int>tree[maxn];

void init()
{
    for(int i=0;i<=n;i++) tree[i].clear();
    memset(dp,0,sizeof dp);
    memset(tot,0,sizeof tot);
}

void read()
{
    for(int i=1;i<=n;i++)
    {
        int a,b,c;
        scanf("%d:(%d)",&a,&b);
        while(b--)
        {
            scanf("%d",&c);
            tree[a].push_back(c);
            tot[c]++;
        }
    }
}

void dfs(int now)
{
    if(!tree[now].size())
    {
        dp[now][0]=0;
        dp[now][1]=1;
        return;
    }

    for(int i=0;i<tree[now].size();i++)
        dfs(tree[now][i]);

    for(int i=0;i<tree[now].size();i++)
        dp[now][0]+=dp[tree[now][i]][1];

    for(int i=0;i<tree[now].size();i++)
        dp[now][1]+=min(dp[tree[now][i]][1],dp[tree[now][i]][0]);
    dp[now][1]++;
}

void work()
{
    int ans=0;
    for(int i=0;i<n;i++)
        if(!tot[i])
        {
            dfs(i);
            ans=ans+min(dp[i][1],dp[i][0]);
        }
    printf("%d
",ans);
}

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        read();
        work();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5182328.html