【BZOJ2427】[HAOI2010]软件安装(动态规划,Tarjan)

【BZOJ2427】[HAOI2010]软件安装(动态规划,Tarjan)

题面

BZOJ
洛谷

题解

看到这类题目就应该要意识到依赖关系显然是可以成环的。
注意到这样一个性质,依赖关系最多只有一个,因此环状的依赖关系一定单独成环,其他点只可能将这个环作为依赖。
那么不成环的话,因为依赖关系只有一个,所以必定成树。
那么如果我们把所有环也给理解为一个单点的话,那么就是有一片森林,做一个树型背包即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define MAX 150
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
struct Line{int v,next;}e[MAX<<2];
int h[MAX],cnt=1,dg[MAX];
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;dg[v]++;}
int dfn[MAX],low[MAX],tim,top,St[MAX],ins[MAX];
int n,m,V[MAX],W[MAX],nvis[MAX],ans;
void Tarjan(int u)
{
	dfn[u]=low[u]=++tim;St[++top]=u;ins[u]=1;
	for(int i=h[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]);
		else if(ins[v])low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		int sw=0,sv=0,v,sz=0;
		do
		{
			v=St[top--];sw+=W[v],sv+=V[v];ins[v]=0;W[v]=V[v]=0;nvis[v]=1;++sz;
			if(u!=v)
				for(int i=h[v];i;i=e[i].next)
					Add(u,e[i].v);
		}while(u!=v);
		W[u]=sw;V[u]=sv;if(sz>1)dg[u]=0;nvis[u]=0;
	}
}
int f[MAX][505],sw[MAX],tmp[505];
void dfs(int u)
{
	if(W[u]<=m)f[u][W[u]]=V[u];sw[u]=W[u];nvis[u]=true;
	for(int i=h[u];i;i=e[i].next)
	{
		int v=e[i].v;if(nvis[v])continue;
		dfs(v);
		for(int j=0;j<=m&&j<=sw[u]+sw[v];++j)tmp[j]=-1e9;
		for(int j=0;j<=sw[u];++j)
			for(int k=0;k<=sw[v]&&j+k<=m;++k)
				tmp[j+k]=max(tmp[j+k],f[u][j]+f[v][k]);
		sw[u]+=sw[v];
		for(int j=0;j<=m&&j<=sw[u];++j)f[u][j]=max(f[u][j],tmp[j]);
	}
	f[u][0]=0;
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;++i)W[i]=read();
	for(int i=1;i<=n;++i)V[i]=read();
	for(int i=1;i<=n;++i)
	{
		int x=read();
		if(x)Add(x,i);
	}
	for(int i=1;i<=n;++i)if(!dfn[i])Tarjan(i);
	for(int i=1;i<=n;++i)if(!dg[i])Add(0,i);
	memset(f,-63,sizeof(f));dfs(0);
	for(int i=0;i<=m;++i)ans=max(ans,f[0][i]);
	printf("%d\n",ans);
	return 0;
}
posted @ 2018-10-30 20:25  小蒟蒻yyb  阅读(260)  评论(0编辑  收藏  举报