HDU_1054 树形DP水题(树形DP小结)

给树形DP写给小结:树形DP大致就是在在树上找递推关系。对于节点i:找其父节点fa,其子节点j之间的关系(就是向上推和向下推的做法)。一般的题目就是找子节点的关系:HDU_1054,,ZOJ_2834,HDU_1520,同时找父节点和子节点的HDU_2196。其实应该怎么找,题目读完了基本就知道了。其次还有的就是该节点的状态:dp[i][N]代表这个节点有N种状态,一种状态的好像比较少,两种状态的HDU_1054,HDU_1520,HDU_2196,三种状态的:ZOJ_2834。基本就是这些了。。。下面来说这道题:

直接给状态转移方程:

dp[u][0] = sum{dp[v][1]};  代表u节点没有士兵

dp[u][1] =1+sum{dp[v][1],dp[v][0]}; 代表u节点有士兵

下面贴代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <vector>
#define ll  long long
#define FOR(i,x,y)  for(int i = x;i < y;i ++)
#define INF 1111111111

using namespace std;

const int MAXN = 1600;

//dp[i]代表第i个节点以及其子树的所有节点都被覆盖所需要的最少士兵数
int n,dp[MAXN][2];    //dp[i][0]代表第i个点没有士兵,dp[i][1]代表第i个点有士兵
vector <int> G[MAXN];

void dfs(int u,int fa){
    vector <int> :: iterator it;
    dp[u][0] = 0;
    dp[u][1] = 1;
    int d_value = INF;
    for(it = G[u].begin();it != G[u].end();it ++){
        int v = *it;
        if(v == fa) continue;
        dfs(v,u);
        d_value = min(d_value,dp[v][1]-dp[v][0]);
        dp[u][0] += dp[v][1];
        dp[u][1] += min(dp[v][0],dp[v][1]);
    }
}

void init_input(){
    FOR(i,0,n)  G[i].clear();
    int u,v,cnt;
    char str[30];
    FOR(i,0,n){
        scanf("%s",str);
        u = atoi(str);
        int len = strlen(str);
        FOR(i,0,len)
            if(str[i] == '(')   {cnt = atoi(str+i+1); break;}
        FOR(i,0,cnt){
            scanf("%d",&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
    }
}

int main()
{
    while(~scanf("%d",&n)){
        init_input();
        dfs(0,-1);
        if(n==1)    printf("1
");
        else printf("%d
",min(dp[0][0],dp[0][1]));
    }
    return 0;
}



原文地址:https://www.cnblogs.com/hqwhqwhq/p/4555875.html