POJ1463 Strategic game

POJ1463

题 意:给定一个树,求一个最少的节点集合,以至于每一条至少有一个节点在这个在这个集合中。
数据范围:
0 < n <= 1500
输入样例:

4
0:(1) 1     //0代表父节点 //括号里面的1 代表子节点的个数 之后就是子节点编号
1:(2) 2 3   
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)

输入样例:

1
2

思 路: 这里只给出树形dp的思路,对于每一个节点,都有两种决策,放或者不放。树形dp的核心思路是递归,从子节点一次把最优的状态往上传。那么为什么这题可以用树形dp呢。因为这题用树形dp确实可以求出最优解。
dp[v][1] 表示节点放入这个最小集合set,dp[v][0]表示不放入
那么父节点放入了,子节点可以放入,也可以不放入,取决于子节点的状态。如果父节点没有放入,那么子节点必须放入。状态转移方程:
dp[v][1] += min(dp[u][0],dp[u][1])
dp[v][0] += dp[u][1]

关键点 确定这是一个树形dp的题型。
关键点 判断怎么用树形dp的状态也是一个关键点。
关键点 状态转移方程。

收 获: 对树形dp有了更深刻的理解。

//每个点都可以选择放或者不放
//我们要求的是最少的,可以监视稍有的节点.
//关键点1:状态转移方程
//dp[i][1] 表示第i个节点放
//dp[i][0] 表示第i个节点不放
//dp[i][1] = min(dp[u][0],dp[u][1]);
//dp[i][0] += dp[u][1]

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 6e3+5;
int dp[maxn][2];
int parent[maxn];
int n;
void tree_dp(int root){
    for(int i=1;i<=n;i++){
        if(parent[i] == root){
            tree_dp(i);
            dp[root][1] += min(dp[i][1],dp[i][0]);
            dp[root][0] += dp[i][1];
        }
    }
}
int main() {
    while(~scanf("%d",&n)){
        memset(parent,0,sizeof(parent));
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){
            dp[i][1] = 1;
            int f,cs;
            scanf("%d:(%d)",&f,&cs);
            f = f+1;
            for(int i=0;i<cs;i++){
                int temp;
                scanf("%d",&temp);
                temp = temp+1;
                parent[temp] = f;
            }
        }
        int root = 1;
        while(parent[root]!=0){
            root = parent[root];
        }

        tree_dp(root);
        int MAX = min(dp[root][0],dp[root][1]);
        printf("%d\n",MAX);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37129433/article/details/81123011