• [tarjan][树形dp] 洛谷 P2515 软件安装


    题目描述

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

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

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

    输入输出格式

    输入格式:

    第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 )

    输出格式:

    一个整数,代表最大价值

    输入输出样例

    输入样例#1:
    3 10
    5 5 6
    2 3 4
    0 1 1
    输出样例#1:
    5

    题解

    • 首先,一个软件只能依赖一个软件,那么我们将被依赖的软件向依赖它的软件上连一条边,这么发现,每个点的入度为1
    • 每个点入度为1的图是什么,那就是树,但是这棵树有可能会形成环,然后就要打tarjan缩环
    • 设f[i][j]为以i根的树,容量为j的最大价值(不处理根),那么答案就是f[0][m]
    • 状态转移方程就很显然了,类似于在树上做一个背包,取一个点的前提条件是它的根被取了
    • f[i][j]=max(f[i][j],f[ik][j]+f[son][kw[son]]+v[son])(k为枚举的一个容量)

    代码

     1 #include <cstdio> 
     2 #include <iostream>
     3 using namespace std;
     4 struct edge { int to,from; }e[110];
     5 int n,m,cnt,tot,k,w[110],v[110],head[110],low[110],dfn[110],vis[110],sta[110],bel[110],w1[110],v1[110],s[110],g[110][110],f[110][510];
     6 void insert(int x,int y) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; }
     7 void tarjan(int x)
     8 {
     9     dfn[x]=low[x]=++dfn[0],sta[++sta[0]]=x,vis[x]=1;
    10     for (int i=head[x];i;i=e[i].from)
    11         if (!dfn[e[i].to]) 
    12         {
    13             tarjan(e[i].to);
    14             low[x]=min(low[x],low[e[i].to]);
    15         }
    16         else if (vis[e[i].to]) low[x]=min(low[x],dfn[e[i].to]);
    17     if (dfn[x]==low[x])
    18     {
    19         tot++;
    20         do
    21         {
    22             k=sta[sta[0]--],vis[k]=0;
    23             bel[k]=tot,w1[tot]+=w[k],v1[tot]+=v[k];
    24         }
    25         while (k!=x);
    26     }
    27 }
    28 void dfs(int x)
    29 {
    30     for (int i=1;i<=tot;i++)
    31         if (g[x][i])
    32         {
    33             dfs(i);
    34             for (int j=m;j>=w1[i];j--) for (int k=w1[i];k<=j;k++) f[x][j]=max(f[x][j],f[i][k-w1[i]]+v1[i]+f[x][j-k]);
    35         }
    36 }
    37 int main()
    38 {
    39     scanf("%d%d",&n,&m);
    40     for (int i=1;i<=n;i++) scanf("%d",&w[i]);
    41     for (int i=1;i<=n;i++) scanf("%d",&v[i]);
    42     for (int i=1,x;i<=n;i++)
    43     {
    44         scanf("%d",&x);
    45         if (x) insert(x,i);
    46     }
    47     for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
    48     for (int i=1;i<=n;i++)
    49         for (int j=head[i];j;j=e[j].from)
    50             if (bel[i]!=bel[e[j].to]&&!g[bel[i]][bel[e[j].to]])
    51                 g[bel[i]][bel[e[j].to]]=1,s[bel[e[j].to]]++;
    52     for (int i=1;i<=n;i++) if (!s[i]) g[0][i]=1;
    53     dfs(0);
    54     printf("%d",f[0][m]);
    55 }
  • 相关阅读:
    快速排序算法图文详解(模版使用)
    数据库中事务和隔离级别解析
    详解对象的创建,布局,定位,存活判断
    SpringCloud-Ribbon:认识并配置负载均衡
    SpringCloud-Feign:接口式微服务调用
    SpringCloud-Eureka(3)集群配置和了解CAP原则
    SpringCloud-Eureka(2)服务注册与信息配置
    SpringCloud-Eureka(1)认识Eureka和初步配置
    Promise
    es6
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9833241.html
Copyright © 2020-2023  润新知