POJ 1155 TELE 树形dp

本文介绍了一道关于树形DP的经典问题——如何在保证不亏损的前提下使最多客户端接收比赛广播。通过详细解析题意及算法思路,分享了利用树形DP求解的过程,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://poj.org/problem?id=1155

题意:某电台要广播一场比赛,该电台网络是由N个网点组成的一棵树,其中M个点为客户端,其余点为转发站。客户端i愿支付的钱为pay[i],每一条边需要的花费固定,问电台在保证不亏损的情况下,最多能使多少个客户端接收到信息?广播台所在的节点编号为1。

思路:树形dp。 用dp[root][d] 表示以root为根的子树中,保留d个用户的最大利润,由于每个结点的孩子的数目并不是最多只有两个,因此在求dp[root][d]的时候要进行一次横向的dp,即对root的所有孩子进行一个背包,在具体实现的时候我们可以一次求出root的所有可能d的最大利润(在背包dp的时候一起求出)。

需要注意的几点:1、树最好用邻接矩阵存储,这样可以节约寻找root孩子的时间;

     2、用一个num[ ]数组存储每个root状态数, 即d的最大值,这样比每次都从M开始求用时会少,避免超时。


代码:

#include<stdio.h>
#include<string.h>
#define INF 100000000
#define MAX(a,b) (a) > (b) ? (a) : (b)
int N ,M ;
int pay[3010] ;
int dp[3010][3010] ;
struct Node{
	int d ; 
	int next ;
	int n ;	
}edge[3010] ;
int root[3010] ;
int cnt ;
int num[3010] ;			//存放每个结点的状态种数 

void dfs(int u){
	if(u > N-M){
		num[u] = 1 ;
		dp[u][1] = pay[u] ;
		return ;	
	}	
	dp[u][0] = 0 ;
	for(int i=root[u]; i!=-1; i=edge[i].next){
		int v = edge[i].n ;
		int d = edge[i].d ;
		dfs(v) ;
		num[u] += num[v] ;
		for(int j=num[u];j>=0;j--){			//孩子的背包 
			for(int k=1;j-k>=0 && k<=num[v];k++){
				dp[u][j] = MAX(dp[u][j] , dp[u][j-k]+dp[v][k]-d );	
			}
		}
	}
}
void add(int u , int v, int d){
	edge[cnt].d = d ;
	edge[cnt].n = v ;
	edge[cnt].next = root[u] ;
	root[u] = cnt ++ ;	
}
int main(){
	int a , b ,c ,i, j ;
	while(scanf("%d %d",&N,&M) == 2){
		memset(root , -1  ,sizeof(root) );
		cnt = 0 ;
		for(i=1;i<=N-M;i++){
			scanf("%d",&a);	
			for(j=0;j<a;j++){
				scanf("%d %d",&b,&c);
				add(i,b,c);
			}
		}	
		for(i=N-M+1;i<=N;i++){
			scanf("%d",&pay[i]);				
		}
		for(int i=1;i<=N;i++){
			for(int j=0;j<=M;j++)
				dp[i][j] = -INF ;	
		}
		memset(num , 0 ,sizeof(num));
		dfs(1) ;
		for(int i=num[1];i>=0;i--){
			if(dp[1][i] >= 0){
				printf("%d\n",i);
				break ;	
			}	
		}      
	}	
	return 0 ;	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值