开启了树包支线任务QAQ
我还是弱啊==
这道题原来考过,大概是半年前了,然而现在再回来填坑,却发现还是会的不透彻,颓了颓原来自己的代码T-T
这就是有依赖的背包问题,可以看做分组背包,但是会有很多冗杂的状态,所以我们要对依赖它的“附件”进行一次01背包,把它们泛化
然后我们要把“主件”选上(因为必须要有它),和泛化后的“附件”新组合成物品。当然它也可以单独存在,不选任何“附件”。
当然这道题有坑点:可能有依赖环出现,所以我们要Tarjan缩一下点(最开始一直WA竟然是因为Tarjan打错了,悲伤==)
update:因为是一片森林,所以我们要建一个超级源点233
#include<iostream>
#include<cstdio>
#include<cstdio>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 2011
#define LL long long
using namespace std;
struct haha{
int next,to;
}edge[N*10],edgechu[N*10];
int head[N],cnt=1,headchu[N],cntchu=1;
void add(int u,int v){
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void addchu(int u,int v){
edgechu[cntchu].to=v;
edgechu[cntchu].next=headchu[u];
headchu[u]=cntchu++;
}
int n,m,in[N],wchu[N],vchu[N];
int dfn[N],ji,low[N],hea,instack[N],stack[N];
int cntt,v[N],w[N],belong[N];
void tarjan(int x){
dfn[x]=low[x]=++ji;
instack[x]=1;stack[++hea]=x;
for(int i=headchu[x];i;i=edgechu[i].next){
int to=edgechu[i].to;
if(dfn[to]==-1){
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if(instack[to]) low[x]=min(low[x],dfn[to]);
}
if(low[x]==dfn[x]){
int temp;
cntt++;
while(1){
temp=stack[hea--];
instack[temp]=0;
w[cntt]+=wchu[temp];
v[cntt]+=vchu[temp];
belong[temp]=cntt;
if(temp==x) break;
}
}
}
int f[N][N],root,out[N];
void dfs(int x){
if(out[x]==0){
pos2(i,m,w[x]) f[x][i]=v[x];
return;
}
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
dfs(to);
}
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
pos2(j,m,0){
pos2(k,j,0){
f[x][j]=max(f[x][j],f[x][j-k]+f[to][k]);
}
}
}
pos2(i,m,0){
if(i>=w[x]) f[x][i]=f[x][i-w[x]]+v[x];
else f[x][i]=0;
}
}
int main(){
scanf("%d%d",&n,&m);
pos(i,1,n) scanf("%d",&wchu[i]);
pos(i,1,n) scanf("%d",&vchu[i]);
pos(i,1,n){
int x;scanf("%d",&x);
if(x) addchu(x,i);
}
pos(i,0,n) dfn[i]=-1;
pos(i,1,n) if(dfn[i]==-1) tarjan(i);
pos(x,1,n){
for(int i=headchu[x];i;i=edgechu[i].next){
int to=edgechu[i].to;
if(belong[to]!=belong[x]){
add(belong[x],belong[to]);out[belong[x]]++;in[belong[to]]++;
}
}
}
root=0;
pos(i,1,cntt){
if(in[i]==0){
add(root,i);out[root]++;
}
}
dfs(root);
cout<<f[root][m];
return 0;
}
原文:http://www.cnblogs.com/Hallmeow/p/7747559.html