题面:
题解:
树形dp + 背包
设 dp [ x ] [ i ] 为 从x 点往下共开通 i 个用户的最大值。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
const int maxn=3100;
int head[maxn],ver[maxn],edge[maxn],nt[maxn];
int tot=0;
int dp[maxn][maxn],val[maxn],si[maxn];
int n,m;
void add(int x,int y,int z)
{
ver[++tot]=y,edge[tot]=z;
nt[tot]=head[x],head[x]=tot;
}
void dfs(int x)
{
if(x>=n-m+1)
{
si[x]=1;
dp[x][1]=val[x];
return ;
}
for(int i=head[x];i;i=nt[i])
{
int y=ver[i];
dfs(y);
si[x]+=si[y];
for(int j=si[x];j>=0;j--)
{
for(int k=min(j,si[y]);k>=0;k--)
dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[y][k]-edge[i]);
}
}
}
int main(void)
{
memset(dp,0x80,sizeof(dp));
scanf("%d%d",&n,&m);
int k,y,z;
for(int i=1;i<=n-m;i++)
{
scanf("%d",&k);
for(int j=1;j<=k;j++)
{
scanf("%d%d",&y,&z);
add(i,y,z);
}
}
for(int i=n-m+1;i<=n;i++)
scanf("%d",&val[i]);
for(int i=1;i<=n;i++)
dp[i][0]=0;
dfs(1);
for(int i=m;i>=0;i--)
{
if(dp[1][i]>=0)
{
printf("%d\n",i);
return 0;
}
}
return 0;
}