poj1463——树形DP

本文介绍了一个典型的树形动态规划问题——如何在树的节点上布置哨兵以监控所有边,并给出了解题思路及C++实现代码。

题目链接:

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值