码迷,mamicode.com
首页 > 其他好文 > 详细

[填坑][支线任务]树形DP 树形背包

时间:2017-10-28 18:59:20      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:namespace   tac   def   mes   scan   blog   树形背包   开启   自己   

开启了树包支线任务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 树形背包

标签:namespace   tac   def   mes   scan   blog   树形背包   开启   自己   

原文地址:http://www.cnblogs.com/Hallmeow/p/7747559.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!