您的位置:首页 > 其它

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

2014-08-20 22:25 435 查看
题意简述

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

思路:

         这道题明显有最有子结构和树形的特点,属于树形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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj dp 树形dp 算法