Tarjan水题系列(4):HAOI2010 软件安装
题目:
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
(0≤N≤100,0≤M≤500,0≤Wi≤M,0≤Vi≤1000)
大意:
有向图 选一个节点同时需要选它的前驱,求满足容量关系的最大点权和
思路:
首先依赖关系可以成环 故选了其中一个相当于选了所有 故可以缩点处理
缩完点后 由于一个点只有一个前驱 故剩下的图构成森林 将其与0号点相连构成一个树 此时本题就成了树上背包的裸题 题干疯狂暗示 注意选了父亲才能选儿子故此时状态dp[u][w]是选了u节点后该子树在w容量时取得的最优解 又由于选了u节点故dp[u][w]需要初始化 由状态定义知最终答案在dp[0][M]取得
下面是代码
1 #include <cstdio> 2 #include <iostream> 3 #define r(x) x=read() 4 #define MAXX 1005 5 using namespace std; 6 int f[MAXX][MAXX],w2[MAXX],z2[MAXX],w[MAXX],z[MAXX],sta[MAXX],id[MAXX], 7 low[MAXX],dfn[MAXX],h[2][MAXX],cnt[2],fa[MAXX],k,num,top,n,m,ans,to; 8 struct edge{int to,nex;}e[2][1005]; 9 void add(int u,int to,int d) 10 { 11 cnt[d]++; 12 e[d][cnt[d]]=(edge){to,h[d][u]}; 13 h[d][u]=cnt[d]; 14 } 15 void tarjan(int u) 16 { 17 low[u]=dfn[u]=++k;sta[++top]=u; 18 for(int i=h[0][u];i;i=e[0][i].nex) 19 { 20 int to=e[0][i].to; 21 if(!dfn[to]) 22 tarjan(to),low[u]=min(low[u],low[to]); 23 else 24 if(!id[to]) 25 low[u]=min(low[u],dfn[to]); 26 } 27 if(low[u]==dfn[u]) 28 { 29 id[u]=++num; 30 while(sta[top]!=u) 31 { 32 id[sta[top]]=num; 33 --top; 34 } 35 --top; 36 } 37 } 38 void dfs(int u) 39 { 40 for(int i=w[u];i<=m;++i) f[u][i]=z[u]; 41 for(int p=h[1][u];p;p=e[1][p].nex) 42 { 43 dfs(e[1][p].to); 44 for(int i=m;i>=w[u];--i) 45 for(int j=0;j<=i-w[u];++j) 46 f[u][i]=max(f[u][i],f[u][i-j]+f[e[1][p].to][j]); 47 } 48 } 49 int read() 50 { 51 char ch=0;int w=0; 52 while(ch<'0'||ch>'9'){ch=getchar();} 53 while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();} 54 return w; 55 } 56 int main() 57 { 58 r(n),r(m); 59 for(int i=1;i<=n;++i) 60 r(w2[i]); 61 for(int i=1;i<=n;++i) 62 r(z2[i]); 63 for(int i=1;i<=n;++i) 64 { 65 r(to); 66 if(to) 67 add(to,i,0); 68 } 69 for(int i=1;i<=n;++i) 70 if(!id[i]) 71 tarjan(i); 72 for(int i=1;i<=n;++i) 73 { 74 w[id[i]]+=w2[i]; 75 z[id[i]]+=z2[i]; 76 for(int j=h[0][i];j;j=e[0][j].nex) 77 { 78 if(id[e[0][j].to]!=id[i]) 79 add(id[i],id[e[0][j].to],1),++fa[id[e[0][j].to]]; 80 } 81 } 82 for(int i=1;i<=num;++i) 83 if(!fa[i]) add(0,i,1); 84 dfs(0); 85 printf("%d",f[0][m]); 86 return 0; 87 }