题目大意

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

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

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

题解

根据题目,我们建立图。

显然这个图由一些树和一些scc构成(注意:scc一定不在树上),那么我们可以知道,如果选了scc中的一个点,其他点必须也要选,所以我们把所有的scc缩成一个点,这样就构成了一个森林。

对于一个入度为0的点,我们从一个虚点向其连接一条边,这样图就变成了树。

考虑树形dp,定义f[i][j]为对于i为根的子树总共分配j点权值能拿到的最大value

我们可以有$$f[i][j] = f[k][l] + f[i][j-l]$$

记忆化搜索即可。

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn = 505;
const ll maxm = 1000;
ll n, m, K, s, ans = 0;
ll w[maxn], v[maxn], W[maxn], V[maxn];
ll cnt[maxn], vis[maxn], in[maxn], f[maxn][maxm];
vector<ll> sc[maxn];
vector<ll> vs;
vector<ll> G[maxn];
vector<ll> rg[maxn];
vector<ll> ng[maxn];
void add(ll from, ll to) {
  G[from].push_back(to);
  rg[to].push_back(from);
}
void add_edge(ll from, ll to) {
  in[to] = 1;
  ng[from].push_back(to);
}
void dfs(ll s) {
  vis[s] = 1;
  for (ll i = 0; i < G[s].size(); i++) {
    if (!vis[G[s][i]])
      dfs(G[s][i]);
  }
  vs.push_back(s);
}
void rdfs(ll s, ll k) {
  vis[s] = 1;
  for (ll i = 0; i < rg[s].size(); i++) {
    if (!vis[rg[s][i]])
      rdfs(rg[s][i], k);
  }
  cnt[s] = k;
  sc[k].push_back(s);
}
void scc() {
  memset(vis, 0, sizeof(vis));
  vs.clear();
  for (ll i = 1; i <= n; i++) {
    if (!vis[i])
      dfs(i);
  }
  ll k = 0;
  memset(vis, 0, sizeof(vis));
  for (ll i = vs.size() - 1; i >= 0; i--) {
    if (!vis[vs[i]])
      rdfs(vs[i], k++);
  }
  K = k;
}
void build_graph() {
  for (ll i = 0; i < K; i++) {
    for (ll j = 0; j < sc[i].size(); j++) {
      W[i] += w[sc[i][j]];
      V[i] += v[sc[i][j]];
    }
  }
  for (ll i = 1; i <= n; i++) {
    for (ll j = 0; j < G[i].size(); j++) {
      if (cnt[i] != cnt[G[i][j]])
        add_edge(cnt[i], cnt[G[i][j]]);
    }
  }
  s = K + 1;
  for (ll i = 0; i < K; i++)
    if (!in[i])
      add_edge(s, i);
}
void dp(ll x) {
  for (ll i = 0; i < ng[x].size(); i++) {
    dp(ng[x][i]);
    for (ll j = m - W[x]; j >= 0; j--) { //鏋氫妇閫夊畬鑷繁鍚庤垂鐢?
      for (ll k = 0; k <= j; k++) {      //鏋氫妇缁欏効瀛愮殑璐圭敤
        f[x][j] = max(f[x][j], f[x][k] + f[ng[x][i]][j - k]);
      }
    }
  }
  for (ll j = m; j >= 0; j--) {
    if (j >= W[x])
      f[x][j] = f[x][j - W[x]] + V[x];
    else
      f[x][j] = 0;
  }
}
int main() {
  // freopen("input", "r", stdin);
  scanf("%lld %lld", &n, &m);
  for (ll i = 1; i <= n; i++)
    scanf("%lld", &w[i]);
  for (ll i = 1; i <= n; i++)
    scanf("%lld", &v[i]);
  for (ll i = 1; i <= n; i++) {
    ll x;
    scanf("%lld", &x);
    if (x)
      add(x, i);
  }
  scc();
  build_graph();
  dp(s);
  printf("%lld\n", f[s][m]);
}

[bzoj2427][HAOI2010]软件安装——强连通分量+树形DP的更多相关文章

  1. bzoj2427 [HAOI2010]软件安装——缩点+树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2427 今天的考试题...好不容易一次写对了树形DP,却没发现有环的情况... 发现自己 ta ...

  2. BZOJ 2427 软件安装(强连通分量+树形背包)

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

  3. 洛谷 P2515 [HAOI2010]软件安装(缩点+树形dp)

    题面 luogu 题解 缩点+树形dp 依赖关系可以看作有向边 因为有环,先缩点 缩点后,有可能图不联通. 我们可以新建一个结点连接每个联通块. 然后就是树形dp了 Code #include< ...

  4. bzoj 2427: [HAOI2010]软件安装【tarjan+树形dp】

    一眼最大权闭合子图,然后开始构图,画了画之后发现我其实是个智障网络流满足不了m,于是发现正确的打开方式应该是一眼树上dp 然后仔细看了看性质,发现把依赖关系建成图之后是个奇环森林,这个显然不能直接dp ...

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 破解PHPStrom 10 and Pycharm

    注册时选择 License server http://idea.lanyus.com/ 然后点击OK Pycharm -- License server http://idea.lanyus.com ...

  2. static和final的区别(转载)

    Java中static 和final的区别 final定义的变量可以看做一个常量,不能被改变: final定义的方法不能被覆盖: final定义的类不能被继承. final static 就是再加上s ...

  3. python 基础篇 12 装饰器进阶

    本节主要内容:1. 通⽤装饰器回顾2. 函数的有⽤信息3. 带参数的装饰器4. 多个装饰器同时装饰⼀个函数 ⼀. 通⽤装饰器的回顾开闭原则: 对增加功能开放. 对修改代码封闭装饰器的作⽤: 在不改变原 ...

  4. [Java-Idea]解决idea启动项目报错:Unable to open debugger port(127.0.0.1:53046):java.net.SocketException"socket closed

    命令行窗口,执行命令:netstat -aon|findstr 9030 查找占用端口的进程 taskkill -f -pid 11331

  5. mongodb数据库高级操作

    1.创建索引 2.索引名称 3.其他索引 4.explain 5.操作索引 6.高级特性 7.固定集合 8.导入导出 9.上锁 10.添加用户 11.主从复制

  6. HDU 1693 Eat the Trees(插头DP,入门题)

    Problem Description Most of us know that in the game called DotA(Defense of the Ancient), Pudge is a ...

  7. Qscintilla2编译使用

    Qscintilla2的下载地址: https://github.com/josephwilk/qscintilla https://riverbankcomputing.com/software/q ...

  8. PAT L2-019 悄悄关注

    https://pintia.cn/problem-sets/994805046380707840/problems/994805059731177472 新浪微博上有个“悄悄关注”,一个用户悄悄关注 ...

  9. Redis的高级应用——数据安全

    Redis的数据保存在内存中,速度十分快.这也就意味着,一个恶意破解redis数据库密码的用户,可以在一秒钟进行更多的尝试.如果用户密码级别较低或更换频率过长,就会造成致命的危害. 1.设置用户 Re ...

  10. Java面试题(下)

    这部分主要是开源Java EE框架方面的内容,包括hibernate.MyBatis.spring.Spring MVC等,由于Struts 2已经是明日黄花,在这里就不讨论Struts 2的面试题, ...