我们设(f[i][j])表示在第(i)个节点时转播到(j)个用户的收益减费用的最大值。
现在找递推式:
(f[i][j]=max(f[i][j],f[son][k]+f[i][j-k]-w[i->son]);)
初始值如下(f[i][0]=0,f[leaf][1]=val[leaf])
根据这些我们写出代码如下:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,k;
const int maxn=3005;
int beg[maxn],nex[maxn<<1],to[maxn<<1],w[maxn<<1],e;
inline void add(int x,int y,int z){
e++;nex[e]=beg[x];
beg[x]=e;to[e]=y;w[e]=z;
}
int f[maxn][maxn],sz[maxn];
inline void dfs(int x,int fa){
if(x>=n-m+1)return;
for(int i=beg[x];i;i=nex[i]){
int t=to[i];
dfs(t,x);sz[x]+=sz[t];
for(int j=sz[x];j>=1;j--)
for(int k=0;k<=min(j,sz[t]);k++)
f[x][j]=max(f[x][j],f[t][k]+f[x][j-k]-w[i]);
}
}
int main(){
n=read(),m=read();
int x,y;
for(int i=1;i<=n-m;i++){
k=read();
for(int j=1;j<=k;j++){
x=read(),y=read();
add(i,x,y);
}
}
memset(f,-0x3f,sizeof(f));
for(int i=n-m+1;i<=n;i++)
f[i][1]=read(),sz[i]=1;
for(int i=1;i<=n;i++)
f[i][0]=0;
dfs(1,0);
for(int i=n;i>=0;i--)
if(f[1][i]>=0){
printf("%d
",i);
return 0;
}
}
就成功AC了。
注:复杂度玄学
深深地感到自己的弱小。