POJ 1463 Strategic game(树形DP)

题意:给一棵树,当在某个结点上放置士兵时,与该点相邻的边就被看守住了,求最少需多少士兵才能看住树中所有边。

分析:先将无根树有根化,然后DP。

状态设计:

      1、dp[i][0],表示在结点 i 没放置士兵的情况下,看住以结点 i 为根的子树的所有边所需的最少士兵;

      2、dp[i][1],表示在结点 i 放置士兵的情况下,看住以结点 i 为根的子树的所有边所需的最少士兵。

状态转移:

      1、dp[i][0]=∑dp[j][1],j 是 i 的儿子结点;(根结点不放士兵时,与其相连的边必须由儿子结点来看守)

      2、dp[i][1]=1+∑ ( MIN ( dp[j][0] , dp[j][1] ) ),j 是 i 的儿子结点。 (根结点放士兵时,儿子结点可放可不放)

初始化:  d[i][0]=0,d[i][1]=1,其中 i 是叶子结点

View Code
#include <stdio.h>

#include <string.h>

#include <vector>

using namespace std;



#define N 1510

#define MAX(a,b) ((a)>(b)?(a):(b))

#define MIN(a,b) ((a)<(b)?(a):(b))



int n,p[N],d[N],maxd;

vector<int>g[N];

vector<int>rd[N];

int dp[N][2];



void init()

{

    int i;

    maxd=0;

    for(i=0; i<n; i++)

    {

        g[i].clear();

        rd[i].clear();

    }

    memset(dp,0,sizeof(dp));

}

void read()

{

    int i,j,k,cnt;

    for(k=0; k<n; k++)

    {

        scanf("%d:(%d)",&i,&cnt);

        while(cnt--)

        {

            scanf("%d",&j);

            g[i].push_back(j);

            g[j].push_back(i);

        }

    }

}

void dfs(int u,int fa)

{

    int i,v;

    d[u]=(fa==-1)?0:d[fa]+1;

    rd[d[u]].push_back(u);

    maxd=MAX(maxd,d[u]);

    for(i=0; i<g[u].size(); i++)

    {

        v=g[u][i];

        if(v^fa)    dfs(v,p[v]=u);

    }

}

void DP()

{

    int i,j,u;

    for(i=maxd; i>=0; i--)

    {

        for(j=0; j<rd[i].size(); j++)

        {

            u=rd[i][j];

            dp[u][1]+=1;

            if(i)

            {

                dp[p[u]][0]+=dp[u][1];

                dp[p[u]][1]+=MIN(dp[u][0],dp[u][1]);

            }

        }

    }

    printf("%d\n",MIN(dp[0][0],dp[0][1]));

}

int main()

{

    int i,j,k;

    while(~scanf("%d",&n))

    {

        init();

        read();

        dfs(0,-1);

        DP();

    }

    return 0;

}

 

你可能感兴趣的:(game)