题目大意

现在我们的手头有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. VS2013生产过程问题及解决

    TRK0002错误 现象:编译器.链接器交替报错,不能正常生成 环境:Win8.1 + VS2013 + 百度杀毒 解决:退出百度杀毒,重启VS,再进行生成 修订:发现问题依旧,经过多次试验,发现与杀 ...

  2. 玩转VIM-札记(三)

    玩转VIM-札记(三) 眨眼之间,5月就要从指间溜走,不给人一点点遐想的时间,我要赶紧抓着五月的尾巴,在博客中在添一笔.那么就还接着Vim来说吧.以Vim来为五月画上一个句号. 返璞归真 相信经过玩转 ...

  3. springmvc基础篇—通过注解的方式去配置项目

    学习了通过xml方式去配置项目后,当然要掌握更简单更灵活的注解方式哟,这是官方推荐使用的方式. 一.修改配置文件,建议大家直接使用我的配置文件 <?xml version="1.0&q ...

  4. MySQL☞create语句

    几种常用的建表语句: 1.最简单的建表语句: create table 表名( 列名1 数据类型(长度), 列名2 数据类型(长度), ... ) 2.带主键的建表语句: CREATE TABLE 表 ...

  5. 【Java】Map转换器

    描述: 在控制层接收参数时候, 往往会出现Json格式需要转换为Bean. 通常一两个字段可以用new去save pojo, 但字段多的情况呢? 以下就是为了解决这个尴尬情况,  自己写一个转换工具类 ...

  6. ASP NET Core ---POST, PUT, PATCH, DELETE,Model 验证

    参照 草根专栏- ASP.NET Core + Ng6 实战:https://v.qq.com/x/page/u0765jbwc6f.html 一.POST 安全性和幂等性 安全性是指方法执行后并不会 ...

  7. [P2387魔法森林

    题面 题意: 给出一个图,边权有两维,a与b. 求1到n的一条路径使得路径经过的边的最大的a与b的和最小,输出最小之和. \(Solution:\) 如果做过这题,那么就显得很简单了很好想了. 又是想 ...

  8. OpenCV实现SIFT图像拼接源代码

    OpenCV实现SIFT和KDtree和RANSAC图像拼接源代码,此源代码由Opencv2.4.13.6和VC++实现,代码本人已经调试过,完美运行,效果如附图.Opencv2.4.13.6下载地址 ...

  9. Failed loading D:\Program Files\phpStudy20161103\php\php-5.6.27-nts\ext\php_xdebug.dll

    我用的是phpstudy 更新完composer php 切换composer的国内源的时候老是报找不到\php_xdebug.dll的错误, 原因是, 在php.ini 里面默写就是在Program ...

  10. BZOJ 4276 [ONTAK2015]Bajtman i Okrągły Robin 费用流+线段树优化建图

    Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢 ...