BZOJ 2427: [HAOI2010]软件安装

题目大意:

软件之间有依赖关系,若这款软件依赖的软件能产生贡献且这款软件被安装了则这款软件能产生vi的贡献,同时安装这款软件需要wi的内存。

问内存不超过m时所能得到的最大贡献。

题解:
若依赖关系存在环,显然要使得环中的任意一个软件产生贡献必须把整个环取了。

先缩点,把一个环当成一个物品,然后缩完点的图就是一棵树。

树上一个点被取了,他的父亲也必须被取。

做一遍背包就好了。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,id,ti,cnt,top,in[1000005],x[1000005],f[505][505],last[1000005],dfn[1000005],low[1000005],stack[1000005],instack[1000005],belong[1000005],sw[1000005],sv[1000005],v[1000005],w[1000005];
struct node{
	int to,next;
}e[1000005];
void add(int a,int b){
	e[++cnt].to=b;
	e[cnt].next=last[a];
	last[a]=cnt;
}
void Tarjan(int x,int fa){
	dfn[x]=low[x]=++ti;
	stack[++top]=x;
	instack[x]=1;
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (!dfn[V]){
			Tarjan(V,x);
			low[x]=min(low[x],low[V]);
		}
		else if (instack[V]) low[x]=min(low[x],dfn[V]);
	}
	if (low[x]==dfn[x]){
		id++;
		int now=0;
		while (now!=x){
			now=stack[top--];
			instack[now]=0;
			belong[now]=id;
			sv[id]+=v[now];
			sw[id]+=w[now];
		}
	}
}
void dp(int x){
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		dp(V);
		for (int j=m-sw[x]; j>=0; j--)
			for (int k=0; k<=j; k++)
				f[x][j]=max(f[x][j],f[x][k]+f[V][j-k]);
	}
	for (int j=m; j>=0; j--){
		if (j>=sw[x]) f[x][j]=f[x][j-sw[x]]+sv[x];
		else f[x][j]=0;
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1; i<=n; i++)
		scanf("%d",&w[i]);
	for (int i=1; i<=n; i++)
		scanf("%d",&v[i]);
	for (int i=1; i<=n; i++){
		scanf("%d",&x[i]);
		if (x[i]) add(x[i],i);
	}
	for (int i=1; i<=n; i++)
		if (!dfn[i]) Tarjan(i,0);
	cnt=0;
	memset(last,0,sizeof(last));
	for (int i=1; i<=n; i++)
		if (x[i] && belong[x[i]]!=belong[i]){
			add(belong[x[i]],belong[i]);
			in[belong[i]]++;
		}
	for (int i=1; i<=id; i++)
		if (!in[i]) {
			add(id+1,i);
		}
	dp(id+1);
	printf("%d\n",f[id+1][m]);
	return 0;
}

  

posted @ 2018-04-20 20:12  ~Silent  阅读(169)  评论(0编辑  收藏  举报
Live2D