POJ 1463 Strategic game(树形DP入门)

题意:

给定一棵树, 问最少要占据多少个点才能守护所有边

分析:

树形DP枚举每个点放与不放

树形DP:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1507;
int dp[maxn][2];
//用DP[i][0]来表示该点没有放兵,以这个点为根的子树所需的最少兵数。
//用DP[i][1]来表示该点放兵,以这个点为根的子树所需的最少兵数。

int father[maxn]; //记录每个节点父亲
int vis[maxn];
int N;
int root = 0;
int dfs(int node){
    dp[node][0] = 0, dp[node][1] = 1;
    vis[node] = 1;
    for(int i = 0; i < N; i++){
        if(father[i] == node && !vis[i]){
            dfs(i);
            dp[node][0] += dp[i][1]; //父亲不放, 儿子必须放
            dp[node][1] += min(dp[i][0], dp[i][1]);//父亲节点放了, 取儿子节点的最小值
        }
    }
    return min(dp[node][0], dp[node][1]);
}
int main() {
    while(~scanf("%d", &N)) {
        memset(father, -1, sizeof(father));
        memset(dp, 0, sizeof(dp));
        memset(vis, 0, sizeof(vis));
        int root = -1;
        for(int i = 0; i < N; i++){
            int u ,v ,k;
            scanf("%d:(%d)", &u, &k);
            if(root == -1) root = u; //the first node is root;
            for(int j = 0; j < k; j++){
                scanf("%d", &v);
                father[v] = u;
            }
        }

        cout << dfs(root) << "\n";
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Jadon97/p/9152846.html
今日推荐