POJ1155 - TELE(树形DP)
题目大意
电视台要直播一场比赛,电视网络刚好形成了一棵树,其中有M个为客户端,其他的为中转站,其中中转站与中转站以及中转站与客户端之间连接都需要一定费用,每个客户i愿意支付pay[i]元钱,问电视台在不亏损的情况下,最多可以让多少个客户观看比赛
题解
每个客户要么选要么不选,和01背包差不多,只不过这是在树上进行,我们用dp[u][j]表示以u为根节点选择j个客户的能够获得的最大盈利,dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k])(v为u结点的子结点),最后结果就是dp[1][j](0<=j<=m)中最大的使得dp[1][j]>=0的j(保证不亏损)
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; #define MAXN 3005 #define INF 0x3f3f3f3f struct node { int v,next,w; }; node edge[2*MAXN]; int head[MAXN],dp[MAXN][MAXN],cnt[MAXN],value[MAXN]; void add_edge(int u,int v,int w,int &k) { edge[k].v=v; edge[k].w=w; edge[k].next=head[u]; head[u]=k++; } void dfs(int u) { if(head[u]==-1) { dp[u][1]=value[u]; cnt[u]=1; return; } dp[u][0]=0; for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; int w=edge[i].w; dfs(v); cnt[u]+=cnt[v]; for(int j=cnt[u]; j>=1; j--) for(int k=0; k<=cnt[v]&&k<=j; k++) dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-w); } } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { int k=1; memset(head,-1,sizeof(head)); memset(cnt,0,sizeof(cnt)); memset(dp,-INF,sizeof(dp)); for(int u=1; u<=n-m; u++) { int t; scanf("%d",&t); while(t--) { int v,w; scanf("%d%d",&v,&w); add_edge(u,v,w,k); } } for(int i=n-m+1; i<=n; i++) scanf("%d",&value[i]); dfs(1); for(int i=cnt[1]; i>=0; i--) if(dp[1][i]>=0) { printf("%d\n",i); break; } } return 0; }