P1273 有线电视网
题目大意:
题目描述
某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。
从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和。
现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号。
写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多。
树形DP+分组背包
分组背包的一般形式:
for(int i=1;i<=k;i++){//枚举组数 for(int j=V;j>=0;j--){//枚举重量 for(int p=1;p<=P[i];p++){//枚举每一组中的每一个 f[j]=max(f[j],f[j-c[p]]+w[p]); } } }
奉上代码:
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; vector<pair<int,int> >G[3005]; int n,m,val[3005],dp[3005][3005]; int dfs(int u){ if(u>n-m){ dp[u][1]=val[u]; return 1; } int size=G[u].size(),sum=0,si; for(int i=0;i<size;i++){ int v=G[u][i].first,W=G[u][i].second; si=dfs(v);//分组个数 sum+=si;//背包容量 for(int j=sum;j>=0;j--) for(int k=1;k<=si&&j-k>=0;k++) dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-W); } return sum; } int main() { scanf("%d%d",&n,&m); for(int k,v,w,i=1;i<=n-m;i++){ scanf("%d",&k); while(k--){ scanf("%d%d",&v,&w); G[i].push_back(make_pair(v,w)); } } for(int i=n-m+1;i<=n;i++) scanf("%d",&val[i]); //初始化 memset(dp,~0x3f,sizeof(dp));//赋极大负值 for(int i=1;i<=n;i++) dp[i][0]=0; dfs(1); for(int i=m;i>=1;i--) if(dp[1][i]>=0){ printf("%d",i); break; } return 0; }