Description

现在我们的手头有\(N\)个软件,对于一个软件\(i\),它要占用\(W_i\)的磁盘空间,它的价值为\(V_i\)。我们希望从中选择一些软件安装到一台磁盘容量为\(M\)计算机上,使得这些软件的价值尽可能大(即\(V_i\)的和最大)。

但是现在有个问题:软件之间存在依赖关系,即软件\(i\)只有在安装了软件\(j\)(包括软件j的直接或间接依赖)的情况下才能正确工作(软件\(i\)依赖软件\(j\))。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为\(0\)。

我们现在知道了软件之间的依赖关系:软件\(i\)依赖软件\(D_i\)。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则\(D_i=0\),这时只要这个软件安装了,它就能正常工作。

Solution

明显是树形dp。设\(dp[i][j]\)为以\(i\)号点为根的子树中用不超过\(j\)的空间的最大价值。

但是这道题所给出的条件不能直接构成一棵树,比如\(d[1]=2,d[2]=3,d[3]=1\)这时\(1,2,3\)便形成一个独立的联通块并且构成环。又由于这个环也很特殊:要么都选,要么都不选,所以可以用tarjan将环缩点。新点的\(w=\sum\limits_{e \in \text{该环}}w[e]\),\(v=\sum\limits_{e \in \text{该环}}v[e]\)。

缩点后将原来的联通块之间的边连好后再从\(0\)向每一个加完边后入度为\(0\)的点连一条边,此时就将原图转换为一颗以\(0\)为根的树,然后就可以愉快的树形dp辣。

举个栗子:

如果最开始图是这样的

然后缩点,将\(1,2,3\)缩为\(14\),\(10,11,12,13\)缩为\(15\),然后让\(0\)向几个联通块连边:

这时原图被转换成对答案等价的一棵树,然后\(dfs\)用上述方程进行简单的树上背包就解决了。

code

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm> using namespace std;
const int MAXN = 505;
int n, m, cnt, w[MAXN], a[MAXN], d[MAXN];
int dfn[MAXN], low[MAXN], bel[MAXN], tot, scc, ins[MAXN], sta[MAXN], top;
int W[MAXN], V[MAXN], indeg[MAXN], dp[MAXN][MAXN];
struct edge {
int v;
edge *next;
}pool[MAXN * 2], *head[MAXN];
inline void addedge(int u, int v) {
edge *p = &pool[++cnt];
p->v = v, p->next = head[u], head[u] = p;
}
void tarjan(int u) {
dfn[u] = low[u] = ++tot; sta[++top] = u; ins[u] = 1;
for(edge *p = head[u]; p; p = p->next) {
int v = p->v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(ins[v])
low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]) {
++scc;
while(sta[top + 1] != u) {
bel[sta[top]] = scc;
W[scc] += w[sta[top]];
V[scc] += a[sta[top]];
ins[sta[top--]] = 0;
}
}
}
void solve(int u) {
for(int i = W[u]; i <= m; i++)
dp[u][i] = V[u];
for(edge *p = head[u]; p; p = p->next) {
int v = p->v;
solve(v); int k = m - W[u];
for(int i = k; i >= 0; i--)
for(int j = 0; j <= i; j++)
dp[u][i + W[u]] =
max(dp[u][i + W[u]],
dp[v][j] + dp[u][i + W[u] - j]);
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) scanf("%d", &w[i]);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) {
scanf("%d", &d[i]); if(d[i]) addedge(d[i], i);
}
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i);
for(int i = 0; i <= n; i++) head[i] = NULL; cnt = 0;
for(int i = 1; i <= n; i++)
if(bel[d[i]] != bel[i]) {
addedge(bel[d[i]], bel[i]);
indeg[bel[i]]++;
}
for(int i = 1; i <= scc; i++)
if(!indeg[i]) addedge(0, i);
solve(0);
printf("%d\n", dp[0][m]);
return 0;
}

题解【bzoj2427 [HAOI2010]软件安装】的更多相关文章

  1. [BZOJ2427][HAOI2010]软件安装(Tarjan+DP)

    2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1987  Solved: 791[Submit][Statu ...

  2. bzoj2427:[HAOI2010]软件安装(Tarjan+tree_dp)

    2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1053  Solved: 424[Submit][Statu ...

  3. bzoj2427: [HAOI2010]软件安装

    Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...

  4. [bzoj2427][HAOI2010]软件安装——强连通分量+树形DP

    题目大意 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...

  5. [BZOJ2427]:[HAOI2010]软件安装(塔尖+DP)

    题目传送门 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用${W}_{i}$的磁盘空间,它的价值为${V}_{i}$.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件 ...

  6. BZOJ2427:[HAOI2010]软件安装(树形DP,强连通分量)

    Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...

  7. [BZOJ2427][HAOI2010]软件安装-tarjan缩点-树上dp

    <题面> 这个题真伤人 之前Tarjan和树规都没学好,吃了不少亏,仔仔细细的搞了一天,收获颇丰 先来一个Tarjan的链接:$\mathbb{O}$ 题目的数据比较友好: $dp$不对: ...

  8. BZOJ2427: [HAOI2010]软件安装 tarjan+树形背包

    分析: 一开始我以为是裸的树形背包...之后被告知这东西...可能有环...什么!有环! 有环就搞掉就就可以了...tarjan缩点...建图记得建立从i到d[i]之后跑tarjan,因为这样才能判断 ...

  9. [BZOJ2427][HAOI2010]软件安装(tarjan+树形DP)

    如果依赖关系出现环,那么对于一个环里的点,要么都选要么都不选, 所以每个环可以当成一个点,也就是强连通分量 然后就可以构造出一颗树,然后树形背包瞎搞一下就行了 注意要搞一个虚拟节点当根节点 Code ...

随机推荐

  1. css多行文本溢出显示省略号(…)

    text-overflow:ellipsis属性可以实现单行文本的溢出显示省略号(…).但部分浏览器还需要加宽度width属性. css代码: overflow: hidden; text-overf ...

  2. 【RL系列】Multi-Armed Bandit笔记补充(一)

    在此之前,请先阅读上一篇文章:[RL系列]Multi-Armed Bandit笔记 本篇的主题就如标题所示,只是上一篇文章的补充,主要关注两道来自于Reinforcement Learning: An ...

  3. Linux系统inotify工具安装配置

    inotify主要功能 Inotify 是一个 Linux特性,它监控文件系统操作,比如读取.写入和创建.Inotify 反应灵敏,用法非常简单,并且比 cron 任务的繁忙轮询高效得多.学习如何将 ...

  4. POJ 3675 Telescope(简单多边形和圆的面积交)

    Description Updog is watching a plane object with a telescope. The field of vision in the telescope ...

  5. HDU 3264/POJ 3831 Open-air shopping malls(计算几何+二分)(2009 Asia Ningbo Regional)

    Description The city of M is a famous shopping city and its open-air shopping malls are extremely at ...

  6. Crawling is going on - Beta版本测试报告

    [Crawling is going on - Beta版本] 测试报告 文件状态: [] 草稿 [√] 正式发布 [] 正在修改 报告编号: 当前版本: 2.0.2 编写人: 周萱.刘昊岩.居玉皓 ...

  7. 福大软工1816:Alpha(5/10)

    Alpha 冲刺 (5/10) 队名:第三视角 组长博客链接 本次作业链接 团队部分 团队燃尽图 工作情况汇报 张扬(组长) 过去两天完成了哪些任务: 文字/口头描述: 1.忙于复习,本次无成果 展示 ...

  8. DDB与DIB

    DB与DIB的区别是什么?觉得书上介绍的有点抽象.不容易理解.他们两者之间的区别的“物理意义” [“现实意义”]——姑且这么叫吧,呵呵!被这个问题困扰了很久,所以今天决定好好查资料总结一下,把它彻底搞 ...

  9. js获取某周、某月、下月、某季度的开始日期、结束日期及判断日期第几周

    //格式化日期:yyyy-MM-dd function formatDate(date) {   var myyear = date.getFullYear();   var mymonth = da ...

  10. MVP开发模式的理解

    1.MVP是什么 如果从层次关系来讲,MVP属于Presentation层的设计模式.对于一个UI模块来说,它的所有功能被分割为三个部分,分别通过Model.View和Presenter来承载.Mod ...