比赛转播
Time Limit:10000MS Memory Limit:100000K
Total Submit:25 Accepted:18
Case Time Limit:1000MS
Description
(tele.cpp/.in/.out 时限1s 内存128M)
一个电视网络计划转播一场足球比赛。网络中的传输点和接收点(即用户)可以表示一棵树。这棵树的根是一个传输点,它将转播比赛。树的叶节点是可能要观看这场比赛的用户(他当然可以选择不看比赛,这样就不用交款)。其他非根节点、非叶节点的中间节点为数据的中间传输点。将一个信号从一个传输点传到另一个传输点的花费是给定的。整个转播的费用就是每一个传输费用的总和。
每一个用户(叶节点)都准备付一定的费用来观看这场比赛。电视网络公司要决定是否要给这个用户提供电视信号。例如:给一个叶节点传输信息的花费太大,而这个用户愿意的付款也很少时,电视公司可能选择不给他转播比赛。找到一个传输方案使最多的用户能看到转播比赛,且转播的费用不超过所有接收信号用户的交款。
Input
第一行包含两个整数N和M。N表示分别表示树的节点数,M表示想观看比赛的用户数(叶节点数)。树的根节点用1表示,中间节点的标号为2到N-M,用户的节点标号为N-M+1到N。
接下来的N-M行每行表示一个传输点的信息,第i行表示编号i-1的传输点的信息
每行描述如下:
K A1 C1 A2 C2 …… Ak Ck
表示一个传输点将信号传给K个点,每一个包含两个数A和C,A表示传输点或用户的节点号,C表示传输的花费。
最后一行有M个整数分别表示N-M+1到N号用户看这场比赛愿意的付费。
Output
一行包含一个整数,最大的用户数
Sample Input
样例输入1
5 3
2 2 2 5 3
2 3 2 4 3
3 4 2
样例输入2
5 3
2 2 2 5 3
2 3 2 4 3
4 4 2
样例输入3
9 6
3 2 2 3 2 9 3
2 4 2 5 2
3 6 2 7 2 8 2
4 3 3 3 1 1
Sample Output
样例输出1
2
样例输出2
3
样例输出3
5
Hint
2<=N<=3000,1<=M<=N-1 每次传输的费用和每个用户愿意提供的费用都<=100
树形背包问题
状态:dp[u][j]表示为u根的子树中的j个叶子节点提供直播服务能获得的最多收益(可能为负)
状态转移:dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-w[u][v])
v为u的儿子节点,w[u][v]为u到v所需费用, 0<=j<=Cnt[u] Cnt[u]表示u为根的子树中,叶子节点的总个数
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=3005;
const int inf=1e9;
int n,p,w[maxn],cnt[maxn],start,ct,f[maxn][maxn];
int END[2*maxn],NEXT[2*maxn],LAST[maxn],LEN[2*maxn];
inline void _read(int &x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
void insert(int a,int b,int l){
END[++ct]=b;
LEN[ct]=l;
NEXT[ct]=LAST[a];
LAST[a]=ct;
}
void dp(int u,int fa){
int i,j,k,q;
for(i=LAST[u],j=END[i];i;i=NEXT[i],j=END[i]){
dp(j,u);
cnt[u]+=cnt[j];
for(k=cnt[u];k>=1;k--)
for(q=1;q<=cnt[j];q++)
f[u][k]=max(f[u][k],f[u][k-q]+f[j][q]-LEN[i]);
}
}
int main(){
_read(n);_read(p);
int i,j,t,a,c;
start=n-p+1;
for(i=1;i<start;i++){
_read(t);
for(j=1;j<=t;j++){
_read(a);_read(c);
insert(i,a,c);
}
}
for(i=1;i<=n;i++)
for(j=1;j<=p;j++)
f[i][j]=-inf;
for(i=start;i<=n;i++){
_read(f[i][1]);
cnt[i]=1;
}
dp(1,0);
for(i=p;i>=0;i--)
if(f[1][i]>=0){cout<<i;break;}
}