一、题目
二、分析
dp[i][j] :以i节点为根的子树为j个用户提供服务最大的利润额
状态转移方程:
该题在背包的两层循环上需要特别注意循环范围,以免出现TLE
三、代码
#include<bits/stdc++.h>
using namespace std;
const int N=3010;
int dp[N][N];
int n,m;
int h[N],e[N*2],ne[N*2],w[N*2],idx;
int st[N];
void add(int a,int b,int c)
{
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
int dfs(int root)
{
int sum=0;
for(int i=h[root];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j])
{
st[j]=true;
sum+=dfs(j);
st[j]=false;
for(int a=sum;a>=1;a--)
{
for(int b=1;b<=a&&dp[j][b]!=-50000;b++)
{
dp[root][a]=max(dp[root][a],dp[root][a-b]+dp[j][b]+w[i]);
}
}
}
}
if(sum==0)
return 1;
return sum;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
dp[i][j]=-50000;
for(int i=1;i<=n-m;i++)
{
int k;
cin>>k;
for(int j=1;j<=k;j++)
{
int b,c;
cin>>b>>c;
add(i,b,c*-1),add(b,i,c*-1);
}
}
for(int i=n-m+1;i<=n;i++)
cin>>dp[i][1];
st[1]=true;
dfs(1);
for(int i=m;i;i--)
{
if(dp[1][i]>=0)
{
cout<<i<<endl;
return 0;
}
}
return 0;
}