【洛谷P1273】有线电视网
有线电视网
树形DP,分组背包
dp[u][i][j]表示以u为根的子树,前i个子树中选j个用户的最大收益.
dp[u][size[u]][0]=0;
dp[u][i][j]=max(dp[u][i][j],dp[u][i-1][j-k]+dp[v][size[v]][k]-w[u][v]);
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define N 3010 int n,m,dp[N][N],val[N]; struct NODE{ int to,w,next; } e[N]; int Head[N],num; inline void add(int x,int y,int w){ e[++num].to=y; e[num].w=w; e[num].next=Head[x]; Head[x]=num; } inline int read(){ int x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); } return x; } int dfs(int u){ dp[u][0]=0; if(u>n-m){ dp[u][1]=val[u]; return 1; } int sum=0; for(int i=Head[u];i;i=e[i].next){ int v=e[i].to; int sz=dfs(v); for(int j=sum;j>=0;j--) for(int k=1;k<=sz;k++) dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]-e[i].w); sum+=sz; } return sum+1; } int main() { memset(dp,~0x3f,sizeof(dp)); n=read(); m=read(); int snum,y,w; for(int i=1;i<=n-m;i++){ snum=read(); while(snum--){ y=read(); w=read(); add(i,y,w); } } for(int i=n-m+1;i<=n;i++) val[i]=read(); dfs(1); int ans=0; for(ans=m;ans>=1;ans--) if(dp[1][ans]>=0) break; printf("%d\n",ans); return 0; }