其他分享
首页 > 其他分享> > [解题记录] [HAOI2010]软件安装

[解题记录] [HAOI2010]软件安装

作者:互联网

P2515 [HAOI2010]软件安装

题意简述

现在我们的手头有 \(N\) 个软件,对于一个软件\(i\) ,它要占用 \(W_i\) 的磁盘空间,它的价值为 \(V_i\) ,我们希望从中选择

一些软件安装到一台磁盘容量为 \(M\) 计算机上,使得这些软件的价值尽可能大(即 \(V_i\) 的和最大),软件之间存

在=依赖关系,即软件 \(i\) 只有在安装了软件\(j\) (包括软件 \(j\) 的直接或间接依赖)的情况下才能正确工作(软件 \(i\) 依

赖软件 \(j\) ),幸运的是,一个软件最多依赖另外一个软件


解题思路

可以把软件之间的依赖关系看成一条有向边,只有选择了祖先才能选择孙子结点,这样就可以直接跑树上背包了

但是题目中可能会有环的情况,这个时候就要用 \(tarjan\) 先缩点了,根据题目中的描述可以知道,在环上的点,

要么都选,要么都不选,所以缩点后把环内所有的点的价值的重量都累积起来就行了

但是即便如此,我们依旧无法保证图是一棵树,它有可能是一个森林,所以我们需要建一个虚点,并将它把所有

入度为 \(0\) 的点相连,它的价值和重量都设为 \(0\)

然后就可以开始DP了,设 \(f_{u,i}\) 表示在 \(u\) 这个点,花费 \(i\) 的限制,能获得的最大价值,因为软件之间的依赖关系

所以初始化为 \(f_{u,i}=v_u,i\in [w_u,m]\),分别枚举 \(i∈[0,m−w_u]\) 表示对所有子树的限制,\(j∈[0,i]\) 表示对当

前子树的限制


code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#define int long long
using namespace std;
map<string,int> mp;
const int N=2e5+10;
int cut[N],head[N],ver[N],nxt[N],dfn[N],low[N],dfstime,n,m,c[N],ins[N],vis[N],top,tot,sta[N],cnt,num,sd[N],nxt1[N],head1[N],ver1[N],tot1,was[N],val[N],V[N],f[N],d[N],w[N],in[N],ans,a[N],dp[3000][3000];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
inline void add1(int x,int y){
    ver1[++tot1]=y,nxt1[tot1]=head1[x],head1[x]=tot1;
}
inline void add(int x,int y){
    ver[++tot]=y,nxt[tot]=head[x],head[x]=tot,in[y]++;
}
void tarjan(int u){
    dfn[u]=low[u]=++dfstime;
    sta[++top]=u,ins[u]=1;
    for(int i=head1[u];i;i=nxt1[i]){
	int v=ver1[i];
	if(!dfn[v]){
	    tarjan(v);
	    low[u]=min(low[u],low[v]);
	}
	else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
	int v;cnt++;
	while(v!=u){
	    v=sta[top--],ins[v]=0;
	    sd[v]=cnt;
	    was[cnt]+=w[v];
	    val[cnt]+=a[v];
	}
    }
}
void treedp(int u){
    for(int i=was[u];i<=m;i++) dp[u][i]=val[u];
    for(int e=head[u];e;e=nxt[e]){
	int v=ver[e];
	treedp(v);
	for(int i=m-was[u];i>=0;--i)
	    for(int j=0;j<=i;++j)
		dp[u][i+was[u]]=max(dp[u][i+was[u]],dp[v][j]+dp[u][i+was[u]-j]);
    }
}
signed main(){
    n=read();m=read();
    for(int i=1;i<=n;++i) w[i]=read();
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=n;++i){
	d[i]=read();
	if(d[i]) add1(d[i],i);
    }
    for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;++i){
	int x=sd[d[i]],y=sd[i];
	if(x!=y) add(x,y);
    }
    for(int i=1;i<=cnt;++i) if(!in[i]) add(0,i);
    treedp(0);
    cout<<dp[0][m]<<endl;
    return 0;
}

标签:ch,依赖,int,解题,HAOI2010,软件,include,安装
来源: https://www.cnblogs.com/hhhd-/p/15552273.html