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 }

 

posted @ 2019-05-19 21:44  Dah  阅读(117)  评论(0编辑  收藏  举报