P2016 战略游戏

  一道还算比较好写的“求树的最大独立集”的问题。

  f [ x ] [ 0 ] 表示以x为节点的子树上,在x位置不放士兵时,士兵数量的最小值;

  f [ x ] [ 1 ] 表示以x为节点的子树上,在x位置要放士兵时,士兵数量的最小值;

  那么方程就写出来了,在回溯的时候,对于f [ x ] [ 0 ] ,它的子节点一定都要放,累加f [ x ] [ 1 ] ;那么对于f [ x ] [ 1 ] ,取最小值就可以了。  

  注意边界判断,当你到树的叶子的时候,要在操作 f 之后返回。

  代码如下:

 

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define maxn 2000
struct data
{
    int num,child[maxn];
} node[maxn];
int f[maxn][3],n,root;
bool vis[maxn];
void dp(int x)
{
    f[x][0]=0;
    f[x][1]=1;
    if(!node[x].num) return ;
    for(int i=1;i<=node[x].num;i++)
    {
        dp(node[x].child[i]);
        f[x][0]+=f[node[x].child[i]][1];
        f[x][1]+=min(f[node[x].child[i]][1],f[node[x].child[i]][0]);
    }
}
int main()
{
    memset(f,0x3f,sizeof(f));
    scanf("%d",&n); 
    for(int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d",&x);
        scanf("%d",&node[x].num);
        for(int j=1;j<=node[x].num;j++)
        {
            scanf("%d",&node[x].child[j]);
            vis[j]=1;
        }
    }
    while(vis[root]) root++;
    dp(root);
    printf("%d",min(f[root][0],f[root][1]));
    return 0;
}

   最后想加一句,所谓树形dp,我认为就是想方设法利用刚刚到过(并从那里回来)的点更新现在这个点,更新到最后就是答案了。

猜你喜欢

转载自www.cnblogs.com/popo-black-cat/p/10182644.html