洛谷-1273 有线电视网

本文介绍了一种使用树形动态规划(Tree DP)算法来解决有线电视网转播足球比赛的问题,目标是在不亏本的情况下使观看转播的用户数量最大化。文章详细描述了输入输出格式、样例以及核心算法实现,包括信号传输费用和用户付费的计算。

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

题目描述
某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。
从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和。
现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号。
写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多。
输入输出格式
输入格式:
输入文件的第一行包含两个用空格隔开的整数N和M,其中2≤N≤3000,1≤M≤N-1,N为整个有线电视网的结点总数,M为用户终端的数量。
第一个转播站即树的根结点编号为1,其他的转播站编号为2到N-M,用户终端编号为N-M+1到N。
接下来的N-M行每行表示—个转播站的数据,第i+1行表示第i个转播站的数据,其格式如下:
K A1 C1 A2 C2 … Ak Ck
K表示该转播站下接K个结点(转播站或用户),每个结点对应一对整数A与C,A表示结点编号,C表示从当前转播站传输信号到结点A的费用。最后一行依次表示所有用户为观看比赛而准备支付的钱数。
输出格式:
输出文件仅一行,包含一个整数,表示上述问题所要求的最大用户数。

输入输出样例
输入样例#1:
5 3
2 2 2 5 3
2 3 2 4 3
3 4 2

输出样例#1:
2

解释:树形DP ,dp[root][num]:dp[root][num]:dp[root][num]rootrootroot为根,选numnumnum个用户最多能赚的钱,那么
dp[root][i+j]=max(dp[root][i+j],dp[root][i]+dp[son][j]−wroot_son)dp[root][i+j]=max(dp[root][i+j],dp[root][i]+dp[son][j]-w_{root\_son})dp[root][i+j]=max(dp[root][i+j],dp[root][i]+dp[son][j]wroot_son)
最后统计dp[1][num]≥0dp[1][num] \ge 0dp[1][num]0点就好了

#include<iostream>
#include<cstring>
#define INF 1000000009
#define N 3005
using namespace std;
int head[N]={0};
int nex[2*N]={0};
int W[2*N]={0};
int to[2*N]={0};
int V[N]={0};
int dp[N][N]={0};
int num[N]={0};
int tot=0;
int n=0,m=0;
void add(int x,int y,int c){
	tot++;
	nex[tot]=head[x];W[tot]=c;to[tot]=y;
	head[x]=tot;
}
void DP(int u,int fa){
	if(u>n-m){
		num[u]++;
		dp[u][1]=V[u];
	}
	for(int i=head[u];i;i=nex[i]){
		int v=to[i],w=W[i];
		if(v==fa) continue;
		DP(v,u);
		for(int j=num[u];j>=0;j--){
			for(int k=num[v];k>=1;k--){
				dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]-w);
			}
		}
		num[u]+=num[v];
	}
}
int main(){
	ios::sync_with_stdio(false);
	for(int i=0;i<N;i++) for(int j=0;j<N;j++) dp[i][j]=-INF;
	for(int i=0;i<N;i++) dp[i][0]=0;
	//freopen("C:\\Users\\24867\\Desktop\\in.txt","r",stdin);
	cin>>n>>m;
	for(int i=1;i<=n-m;i++){
		int k=0,a=0,c=0;cin>>k;
		for(int j=1;j<=k;j++){
			cin>>a>>c;add(i,a,c);add(a,i,c);
		}
	}
	for(int i=1;i<=m;i++) cin>>V[n-m+i];
	DP(1,-1);
	int ret=0;
	for(int i=m;i>=0;i--){
		if(dp[1][i]>=0){
			ret=i;break;
		}
	}
	cout<<ret<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值