Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装

【洛谷P2515】[HAOI2010]软件安装

题目描述

现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。

但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。

我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

Tarjan+树形背包。

Tarjan就是为了恶心人的,注意建边。

模了第一篇题解大佬的奇淫技巧,对于fa是0的点,可以不去管它,等到缩完点重新建边之后,我们统计每个点的入度,如果该点入度为零,那么说明这个点是森林中一棵树的树根,那么这个时候我们再建立超级源点就可以了。

不然的话再所点之前建立超级源点真的恶心,深受其害。。。

至于树形DP,这道题和选课基本上一样,不过我发现了一种更好的有依赖的树形DP的写法,也算是现在才真正学会。

模板:

code:

void dfs(int u){
	for(int i=w[u];i<=n;i++)f[u][i]=v[u];
    for(int i=head[i];i;i=edge[i].nxt){
		int v=edge[i].to;
        dfs(v);
        for(int j=m;j>=w[u];j--){
			for(int k=0;k<=j-w[u];k++){
				f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
            }	
        }
    }
}

code:

#include <iostream>
#include <cstdio>

using namespace std;

const int wx=1017;

inline int read(){
	int sum=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
	return sum*f;
}

int num1,num2,n,m,top,tot,col;
int head1[wx],head2[wx],dfn[wx],low[wx],st[wx];
int belong[wx],f[wx][wx],tmp[wx];
int w[wx],v[wx],W[wx],V[wx],fa[wx];

struct node{
	int nxt,to;
}edge1[wx*2];

struct e{
	int nxt,to;
}edge2[wx*2];

void add1(int from,int to){
	edge1[++num1].nxt=head1[from];
	edge1[num1].to=to;
	head1[from]=num1;
}

void add2(int from,int to){
	edge2[++num2].nxt=head2[from];
	edge2[num2].to=to;
	head2[from]=num2;
}

void Tarjan(int u){
	dfn[u]=low[u]=++tot;
	st[++top]=u;
	for(int i=head1[u];i;i=edge1[i].nxt){
		int v=edge1[i].to;
		if(!dfn[v]){
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(!belong[v]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u]){
		belong[u]=++col;
		while(st[top]!=u){
			belong[st[top]]=col;
			top--;
		}
		top--;
	}
}

void CQ(){
	for(int i=1;i<=n;i++){
		if(belong[i]!=belong[fa[i]]&&fa[i]){
			add2(belong[fa[i]],belong[i]);
			tmp[belong[i]]++;
		}
	}
	for(int i=1;i<=n;i++){
		W[belong[i]]+=w[i];
		V[belong[i]]+=v[i];
	}
	for(int i=1;i<=col;i++){
		if(!tmp[i])add2(col+1,i);
	}
}

void dfs(int u){
	for(int i=W[u];i<=m;i++)f[u][i]=V[u];
	for(int i=head2[u];i;i=edge2[i].nxt){
		int v=edge2[i].to;
		dfs(v);
		for(int j=m;j>=W[u];j--){
			for(int k=0;k<=j-W[u];k++){
				f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
			}
		}
	}
}

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++){
		fa[i]=read();
		if(!fa[i])continue;
		add1(fa[i],i);
	}
	for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
	CQ();
	dfs(col+1);
	printf("%d\n",f[col+1][m]);
	return 0;
}
posted @ 2018-10-15 20:06  _王小呆  阅读(116)  评论(0编辑  收藏  举报