题目链接:http://poj.org/problem?id=1155
题解:
懵。。。。
这题好像就是01背包吧
我们用f[x][j+k]来表示以x为根的子树,转播j+k个用户时,能获得的利润
f[x][j+k]=max(f[x][j+k],f[x][j]+f[son][k]-w);(w表示转播需付出的代价);
我们先处理好所有的f[son][k]然后来更新当前答案;
程序:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; struct ding{ int to,l,next; }edge[10010]; int n,m,cnt,head[5000],num[5000],dp[5000][5000],tem[5000]; void add(int u,int v,int val) { edge[++cnt].to=v;edge[cnt].l=val;edge[cnt].next=head[u];head[u]=cnt; } void dfs(int x) { for (int i=head[x];i;i=edge[i].next) { int y=edge[i].to,w=edge[i].l; dfs(y); for (int j=0;j<=num[x];j++) tem[j]=dp[x][j]; //我们要先备份,因为在更新过程中,使用到的dp[x][j]也会被更新 for (int j=0;j<=num[x];j++) for (int k=0;k<=num[y];k++) dp[x][j+k]=max(dp[x][j+k],tem[j]+dp[y][k]-w); //更新 num[x]+=num[y]; //一个剪枝,有几个叶子节点,我们就没举几个 } } int main() { int k,x,y; scanf("%d%d",&n,&m); for (int i=1;i<=n-m;i++) { scanf("%d",&k); for (int j=1;j<=k;j++) { scanf("%d%d",&x,&y); add(i,x,y); } } for (int i=n;i>=1;i--) for (int j=1;j<=m;j++) dp[i][j]=-210000000; for (int i=n-m+1;i<=n;i++) { scanf("%d",&dp[i][1]); //预处理 num[i]=1; } dfs(1); for (int i=m;i>=0;i--) if (dp[1][i]>=0) //如果不亏钱的话 { printf("%d\n",i); break; } return 0; }