题目链接:
http://poj.org/problem?id=1463
题目大意:
给定一棵树,现在让你在节点处布置哨兵,每个哨兵可以监管与之连接的边。
求监管所有的边最少需要多少哨兵。
解题思路:
比较典型的树形DP。
有点类似之前写过的请人聚会,但是上司和下属不能同时请,最多能请多少人的那个题目。
这个题目的状态转移方程是比较好写的。
dp[i][1]+=min(dp[j][0],dp[j][1]); //当前节点布置哨兵需要的最少人数
dp[i][0]+=dp[j][1]; //当前节点不布置哨兵需要的最少人数
如果当前节点上布置了哨兵,那其孩子节点可以布置也可以不布置哨兵,我们取较小值进行累加。
如果当前节点没有布置哨兵,那其孩子节点必须布置哨兵,直接进行累加。
即可得到当前节点的数据。
从下往上一直推,用dfs实现。
即可得到根节点的安排哨兵和不安排哨兵的所需的人数,取较小值。
源代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#include<iostream>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const double eps=1e-8;
int dp[1505][2];
struct node
{
int pre;
vector<int> child;
}p[1505];
int N;
void dfs(int now)
{
int i,j,k,t,size,child;
size=p[now].child.size();
if(size==0) return;
for(i=0;i<size;i++)
{
child=p[now].child[i];
dfs(child);
dp[now][0]+=dp[child][1];
dp[now][1]+=min(dp[child][1],dp[child][0]);
}
return;
}
int main()
{
freopen("in.txt","r",stdin);
int i,j,c,a,b,size,root;
while(scanf("%d",&N)==1)
{
//节点下标从1开始,所以输入的节点都+1
memset(p,0,sizeof(p));
root=-1;
for(i=1;i<=N;i++)
{
scanf("%d:(%d)",&a,&b); //a表示父亲节点,b表示孩子节点的个数
++a;
if(root==-1) root=a; //第1个输入的节点为根节点
while(b--)
{
scanf("%d",&c);
++c;
p[c].pre=a;
p[a].child.push_back(c);
}
}
memset(dp,0,sizeof(dp));
for(i=1;i<=N;i++)
dp[i][1]=1;
dfs(root);
printf("%d\n",min(dp[root][1],dp[root][0]));
}
return 0;
}
本文介绍了一个典型的树形动态规划问题——如何在树的节点上布置哨兵以监控所有边,并给出了解题思路及C++实现代码。
1570

被折叠的 条评论
为什么被折叠?



