这个题用优化后的依赖背包做难以实现,所以用常规的泛化物品的和来做即可
每个节点的容量定义为这个节点下的叶子结点个数,dp[u][j]用来表示节点u下选取j个物品的最大收益,最后从m-0查询dp[1][i],一旦发现是非负数,i则是答案
需要注意的地方:初始化时将所有的dp[i][0]都赋值为0,一个都不选,代价当然是0
dfs遇到u是叶子结点,那么dp[u][1]定义为这个结点的权值,其余状态用-inf来表示不可达
其余状态全部赋初始值为-inf,表示目前不可达
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define N 3005 struct Edge{int to,nxt,w;}e[N<<1]; int head[N],tot,n,m; void add(int u,int v,int w){ e[tot].to=v;e[tot].nxt=head[u];e[tot].w=w;head[u]=tot++; } int dp[N][N],a[N],size[N]; void dfs1(int u,int pre){ for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==pre)continue; dfs1(v,u);size[u]+=size[v]; } } void dfs2(int u,int pre){ if(a[u]){dp[u][1]=a[u];return;} for(int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if(v==pre)continue; dfs2(v,u); for(int j=size[u];j>=0;j--) for(int k=0;k<=size[v];k++) dp[u][j]=max(dp[u][j],dp[v][k]-e[i].w+dp[u][j-k]); } } int main(){ memset(head,-1,sizeof head); cin>>n>>m; for(int i=1;i<=n-m;i++){ int k,v,w;cin>>k; while(k--){ cin>>v>>w; add(i,v,w);add(v,i,w); } } for(int i=n-m+1;i<=n;i++) cin>>a[i],size[i]=1; memset(dp,-0x3f,sizeof dp); for(int i=1;i<=n;i++)dp[i][0]=0; dfs1(1,1);dfs2(1,1); for(int i=m;i>=0;i--) if(dp[1][i]>=0){ cout<<i<<endl; break; } }
原文地址:https://www.cnblogs.com/zsben991126/p/11385191.html
时间: 2024-10-05 05:49:54