BZOJ2427: [HAOI2010]软件安装

2427: [HAOI2010]软件安装

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1512  Solved: 584
[Submit][Status][Discuss]

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

HINT

Source

 
【题解】
先缩点。
两种解法。
 
‘’1、若把当前图中的每个结点成1个物品,磁盘空间当成背包,则类似有依赖关系的背包问题,可以用动态规划解决。
将所有的树重新编号,设共有x棵树,每棵树的根结点的编号r[1],r[2],…,r[x];
设f(r[i],j)表示第i棵树前拥有j的资源,则

tree(r[i],k)表示第i棵树拥有k资源的最大代价,这个值可以用上述公式处理即,去掉根后转化森林,用背包问题解决。
1<=i<=N, 0<=k<=j<=M
时间复杂度O(NM2)

2、将森林转化为二叉树后,采用树型动态规划一次求出。


设f(i,j)表示以i为根结点的二叉树分配j资源的最大价值
‘’
——by 朱全民
这里采用第二种
做得时候注意,森林->二叉树要虚一个空节点作为根,不能任选一棵树的根作根(被卡了四个点)
 
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <cmath> 
  6 #include <algorithm>
  7 #define min(a, b) ((a) < (b) ? (a) : (b))
  8 #define max(a, b) ((a) > (b) ? (a) : (b))
  9 
 10 inline void read(int &x)
 11 {
 12     x = 0;char ch = getchar(), c = ch;
 13     while(ch < '0' || ch > '9')c = ch, ch = getchar();
 14     while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
 15     if(c == '-')x = -x;
 16 }
 17 
 18 const int INF = 0x3f3f3f3f; 
 19 const int MAXN = 100 + 10;
 20 const int MAXM = 500 + 10;
 21 
 22 int n,m,cost[MAXN],value[MAXN];
 23 
 24 struct Edge
 25 {
 26     int u,v,next;
 27     Edge(int _u, int _v, int _next){u = _u;v = _v;next = _next;}
 28     Edge(){}
 29 }edge[MAXN << 1];
 30 int head[MAXN], cnt;
 31 
 32 inline void insert(int a, int b)
 33 {
 34     edge[++cnt] = Edge(a, b, head[a]);
 35     head[a] = cnt;
 36 }
 37 
 38 int b[MAXN],bb[MAXN],low[MAXN],dfn[MAXN],belong[MAXN],group,tot,stack[MAXN],top;
 39 
 40 void tarjan_dfs(int u)
 41 {
 42     dfn[u] = low[u] = ++tot;    
 43     b[u] = bb[u] = 1;
 44     stack[++top] = u;
 45     for(register int pos = head[u];pos;pos = edge[pos].next)
 46     {
 47         int v = edge[pos].v;
 48         if(!b[v])
 49         {
 50             tarjan_dfs(v);
 51             low[u] = min(low[u], low[v]);
 52         }
 53         else if(bb[v] && low[u] > dfn[v])
 54             low[u] = dfn[v];
 55     }
 56     if(low[u] == dfn[u])
 57     {
 58         ++ group;
 59         int now = 0;
 60         while(now != u)
 61         {
 62             now = stack[top --];
 63             belong[now] = group;
 64             bb[now] = false;
 65         }
 66     }
 67 }
 68 
 69 int cost2[MAXN],value2[MAXN],l[MAXN],r[MAXN],fa2[MAXN];
 70 
 71 void tarjan()
 72 {
 73     for(register int i = 1;i <= n;++ i) if(!b[i]) tarjan_dfs(i);
 74     for(register int u = 1;u <= n;++ u)
 75     {
 76         for(register int pos = head[u];pos;pos = edge[pos].next)
 77         {
 78             int v = edge[pos].v;
 79             if(belong[v] != belong[u])
 80                 fa2[belong[v]] = belong[u];
 81         }
 82         cost2[belong[u]] += cost[u];
 83         value2[belong[u]] += value[u]; 
 84     }
 85     for(register int i = 1;i <= group;++ i)
 86         if(fa2[i])r[i] = l[fa2[i]], l[fa2[i]] = i;
 87 }
 88 
 89 int dp[MAXN][MAXM],dpb[MAXN];
 90 
 91 void DP(int u)
 92 {
 93     if(!u || dpb[u])return; 
 94     dpb[u] = 1;
 95 /*
 96 dp[i][j]表示i和i右边的兄弟消耗磁盘空间j的最大价值
 97 dp[i][j] = max{
 98 选    f[l[i]][a] + f[r[i]][j - a  - cost[i]] + value[i] 
 99 
100 不选  f[r[i]][j]
101 }
102 */
103     DP(l[u]), DP(r[u]);
104     for(register int j = 0;j <= m;++ j)
105     {
106         for(register int a = 0;a <= m;++ a)
107         {
108             //dp[u][j] = max(dp[u][j], dp[u][j - 1]);
109             if(j - a - cost2[u] >= 0)    dp[u][j] = max(dp[u][j], dp[l[u]][a] + dp[r[u]][j - a - cost2[u]] + value2[u]);
110             dp[u][j] = max(dp[u][j], dp[r[u]][j]);
111         }
112     } 
113 }
114 
115 int main()
116 {
117     read(n), read(m);
118     register int tmp;
119     for(register int i = 1;i <= n;++ i) read(cost[i]);
120     for(register int i = 1;i <= n;++ i) read(value[i]);
121     for(register int i = 1;i <= n;++ i) 
122     {
123         read(tmp);
124         if(tmp)insert(tmp, i);
125     }
126     tarjan();
127     int root = 1;
128     while(!l[root] && root <= group)++ root;
129     if(root <= group)
130     {
131         while(fa2[root])root = fa2[root];
132         l[group + 1] = root;
133         fa2[root] = group + 1,
134         root = group + 1;
135         ++ group;
136     }
137     else
138         root = group + 1;
139     for(register int i = 1;i <= group;++ i) 
140         if(!fa2[i] && i != root) r[i] = l[root], l[root] = i, fa2[i] = root;
141     cost2[root] = value2[root] = 0;
142     DP(root);
143     printf("%d", dp[root][m]);
144     return 0;
145 }
BZOJ2427

 

posted @ 2017-09-10 23:56  嘒彼小星  阅读(158)  评论(0编辑  收藏  举报