[HAOI 2010]软件安装

Description

现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

Input

第1行:N, M  (0<=N<=100, 0<=M<=500)
      第2行:W1, W2, ... Wi, ..., Wn (0<=Wi<=M )
      第3行:V1, V2, ..., Vi, ..., Vn  (0<=Vi<=1000 )
      第4行:D1, D2, ..., Di, ..., Dn (0<=Di<=N, Di≠i )

Output

一个整数,代表最大价值。

Sample Input

3 10
5 5 6
2 3 4
0 1 1

Sample Output

5

题解

比较裸的树上背包...只不过可能成环比较坑。

$tarjan$缩点之后再全部连向一个虚点,直接树形$DP$。

 1 //It is made by Awson on 2017.11.5
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <stack>
 7 #include <queue>
 8 #include <vector>
 9 #include <string>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #define LL long long
16 #define Min(a, b) ((a) < (b) ? (a) : (b))
17 #define Max(a, b) ((a) > (b) ? (a) : (b))
18 #define Abs(x) ((x) < 0 ? (-(x)) : (x))
19 using namespace std;
20 const int N = 100;
21 const int M = 500;
22 
23 int n, m;
24 int W[N+5], V[N+5], w[N+5], v[N+5], d[N+5];
25 struct tt {
26     int to, next;
27 }edge[N+5];
28 int path[N+5], top;
29 int dfn[N+5], low[N+5], cnt_time;
30 stack<int>S;
31 bool vis[N+5], in[N+5];
32 int sccno[N+5], sccnum;
33 int f[N+5][M+5];
34 
35 void tarjan(int x) {
36     dfn[x] = low[x] = ++cnt_time; S.push(x); vis[x] = 1;
37     for (int i = path[x]; i; i = edge[i].next) {
38         if (vis[edge[i].to]) low[x] = Min(low[x], dfn[edge[i].to]);
39         else if (!dfn[edge[i].to]) {
40             tarjan(edge[i].to); low[x] = Min(low[x], low[edge[i].to]);
41         }
42     }
43     if (dfn[x] == low[x]) {
44         sccnum++; int u = -1;
45         do {
46             u = S.top(); S.pop();
47             vis[u] = 0, sccno[u] = sccnum;
48             w[sccnum] += W[u], v[sccnum] += V[u];
49         }while (u != x);
50     }
51 }
52 void dfs(int u) {
53     for (int i = path[u]; i; i = edge[i].next) {
54         dfs(edge[i].to);
55         for (int j = m; j >= 0; j--)
56             for (int k = 0; k <= j; k++)
57                 f[u][j] = Max(f[u][k]+f[edge[i].to][j-k], f[u][j]);
58     }
59     for (int i = m; i >= 0; i--) {
60         if (i-w[u] >= 0) f[u][i] = f[u][i-w[u]]+v[u];
61         else f[u][i] = 0;
62     }
63 }
64 void add(int u, int v) {
65     edge[++top].to = v;
66     edge[top].next = path[u];
67     path[u] = top;
68 }
69 void work() {
70     scanf("%d%d", &n, &m);
71     for (int i = 1; i <= n; i++) scanf("%d", &W[i]);
72     for (int i = 1; i <= n; i++) scanf("%d", &V[i]);
73     for (int i = 1; i <= n; i++) {
74         scanf("%d", &d[i]); add(d[i], i);
75     }
76     for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); 
77     memset(path, 0, sizeof(path)); top = 0;
78     for (int i = 1; i <= n; i++) if (sccno[i] != sccno[d[i]]) add(sccno[d[i]], sccno[i]), in[sccno[i]] = 1;
79     for (int i = 1; i <= sccnum; i++) if (!in[i]) add(0, i);
80     dfs(0);
81     int ans = 0;
82     for (int i = 0; i <= m; i++) ans = Max(f[0][i], ans);
83     printf("%d", ans);
84 }
85 int main() {
86     work();
87     return 0;
88 }

 

posted @ 2017-11-05 11:48  NaVi_Awson  阅读(276)  评论(0编辑  收藏  举报