POJ 1463 Strategic game (树形DP) 解题报告

来源:互联网 发布:大数据公司招聘 编辑:程序博客网 时间:2024/05/16 17:35

题意简述

         有若干结点,结点之间有路相连,构成树形结构,如果在一个结点上放置一个士兵,与这个结点相连的路就可以被监视,现在要监视所有的路,问至少要多少士兵。

思路:

         这道题明显有最有子结构和树形的特点,属于树形DP的基础题目。

         最优子结构:

         dp[i][0]、dp[i][1]分别表示在结点i上不放士兵与放士兵时,以i结点为根的子树被覆盖用到士兵的最少数量。

         状态转移:

设j为i的子节点

         

 

         意思是,如果结点i不放士兵,那么它的各个子节点都要放士兵,所以dp[i][0]的值时各子节点dp[j][1]的累加和;如果结点i上放士兵,那么它的子节点放不放都可以,去小的那个值累加,再加上该节点的1个士兵,就是dp[i][1]的值。

         另外,本题还要注意在输入的时候找出树的根,具体方法是先把第一个点设为根,之后输入时,如果某个点的子节点包含当时设的根,就把这个点设为新的根,当所有输入完成后,可以保证所得的就是树的根。


#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int MAXN = 1505;vector<int> child[MAXN];//存放某个结点的所有直接相连的子节点int dp[MAXN][2];void dfs(int rt){int dp0 = 0,dp1 = 0,i;if (child[rt].size() == 0){//叶子节点,递归出口dp[rt][1] = 1;//dp[rt][1]表示在这个点上放士兵dp[rt][0] = 0;//dp[rt][0]表示不在这个点上不放士兵return;}int tmp;for (i = 0; i < child[rt].size(); ++i){tmp = child[rt][i];dfs(tmp);dp1 += min(dp[tmp][1],dp[tmp][0]);//如果这个点放士兵,那么它的子节点可以放也可以不放dp0 += dp[tmp][1];//如果这个点不放士兵,那么它的子节点必须放士兵}dp[rt][1] = dp1 + 1;//加1加的是该节点的这个士兵dp[rt][0] = dp0;}int main(){int n,i,father,root,num,tmp;while (scanf("%d",&n) != EOF){for (i = 0; i < n; ++i)child[i].clear();root = -1;for (i = 0; i < n; ++i){scanf("%d:(%d)",&father,&num);if (root == -1)root = father;while (num--){scanf("%d",&tmp);child[father].push_back(tmp);if (tmp == root)root = father;}}dfs(root);printf("%d\n",min(dp[root][0],dp[root][1]));}return 0;}



0 0
原创粉丝点击