题目:洛谷P2515、BZOJ2427、codevs1866。
题目大意:有n个物品,每个物品有重量和价值,且只能选一次。每个物品可能有一个依赖物品,选了该物品必须先选择它的依赖物品(可能会有环)。给出背包的容量,求可以装物品的最大价值。
解题思路:首先强连通分量缩点,然后树形dp求01背包即可。
C++ Code:
#include<bits/stdc++.h> int n,m,fa[105],w[105],v[105],dfn[105],low[105],idx=0,ys[105],ltfl=0,dad[105]; std::vector<int>a[105]; int f[105][505],W[105],V[105],ans=0,cnt=0,head[105]; bool instack[105]; std::stack<int>s; inline int debian(){ int c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } struct edge{ int to,nxt; }e[66667]; void tarjan(int now){ dfn[now]=low[now]=++idx; s.push(now); instack[now]=true; if(fa[now]){ if(dfn[fa[now]]){ if(instack[fa[now]]&&low[now]>dfn[fa[now]]) low[now]=dfn[fa[now]]; }else{ tarjan(fa[now]); if(low[now]>low[fa[now]])low[now]=low[fa[now]]; } } if(low[now]==dfn[now]){ ++ltfl; int p; do{ p=s.top(); s.pop(); instack[p]=false; a[ltfl].push_back(p); ys[p]=ltfl; W[ltfl]+=w[p]; V[ltfl]+=v[p]; }while(p!=now); } } void dp(int now){ //fprintf(stderr,"233 %d 233 ",now); for(int i=W[now];i<=m;++i) f[now][i]=V[now]; for(int i=head[now];i;i=e[i].nxt){ dp(e[i].to); for(int j=m;j>=W[now];--j){ for(int k=0;k<=m;++k){ if(k+j>m)break; if(f[now][j+k]<f[now][j]+f[e[i].to][k])f[now][j+k]=f[now][j]+f[e[i].to][k]; } } } } int main(){ n=debian(),m=debian(); memset(fa,-1,sizeof fa); for(int i=1;i<=n;++i)w[i]=debian(); for(int i=1;i<=n;++i)v[i]=debian(); for(int i=1;i<=n;++i)fa[i]=debian(); memset(dfn,0,sizeof dfn); memset(W,0,sizeof W); memset(V,0,sizeof V); for(int i=1;i<=n;++i) if(!dfn[i])tarjan(i); //fprintf(stderr,"%d ",ltfl); for(int i=1;i<=n;++i){ if(fa[i]==0||a[ys[i]].size()>1)dad[ys[i]]=0;else dad[ys[i]]=ys[fa[i]]; } memset(f,0,sizeof f); memset(head,0,sizeof head); //for(int i=1;i<=ltfl;++i)fprintf(stderr,"%d: %d %d %d ",i,dad[i],W[i],V[i]); for(int i=1;i<=ltfl;++i){ e[++cnt]=(edge){i,head[dad[i]]}; head[dad[i]]=cnt; } dp(0); for(int i=0;i<=m;++i) if(f[0][i]>ans)ans=f[0][i]; //for(int i=0;i<=ltfl;++i,putchar(' ')) //for(int j=0;j<=m;++j)printf("%d ",f[i][j]); return!printf("%d ",ans); }