1. 程式人生 > >[填坑][支線任務]樹形DP 樹形背包

[填坑][支線任務]樹形DP 樹形背包

adc update next 分組背包 背包問題 == fine long bzoj

開啟了樹包支線任務QAQ

我還是弱啊==

[樹形背包]BZOJ 2427 軟件安裝

這道題原來考過,大概是半年前了,然而現在再回來填坑,卻發現還是會的不透徹,頹了頹原來自己的代碼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;
}

  

[填坑][支線任務]樹形DP 樹形背包