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

题意简述

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

思路:

         这道题明显有最有子结构和树形的特点,属于树形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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值