• cogs 444. [HAOI2010]软件安装


                      ★★☆   输入文件:install.in   输出文件:install.out   简单对比
                          时间限制:1 s   内存限制:128 MB

    【问题描述】
    现在我们的手头有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)

    【输出格式】

    一个整数,代表最大价值。

    【输入样例】
    3 10
    5 5 6
    2 3 4
    0 1 1

    【输出样例】
    5

    题解:

      根据依赖关系可以画出来一张图,有三种可能的情况:1.依赖关系构成一棵树 2.依赖关系构成一个环 3.依赖关系构成一个环下面吊着一棵树。因为有2,3这些情况,所以要先有tarjan预处理一下,缩环为点,重新建图。

      对于建好的图,跑一边树形背包即可,思想类似于01背包,f[x][tot]表示以x为根,容量为tot的最大收益。把x的各个子树看成物品,再枚举每个子树所分给的容量,tot从大到小转移。

      还有一点,f[x][tot]保证x要算进去,最后处理一下即可保证。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<queue>
     8 #include<vector>
     9 using namespace std;
    10 const int maxn=200,maxm=600;
    11 int N,M,W[maxn],V[maxn],fa[maxn];
    12 int val[maxn],cost[maxn],f[maxn][maxm];
    13 
    14 vector<int> to[maxn],son[maxn];
    15 int stac[maxn],top=0,dfn[maxn],low[maxn],inkin[maxn],tot,Index;
    16 bool instac[maxn];
    17 vector<int> kin[maxn];
    18 inline void tarjan(int x){
    19     dfn[x]=low[x]=Index++;
    20     stac[++top]=x;
    21     instac[x]=true;
    22     for(int i=0;i<to[x].size();i++){
    23         int y=to[x][i];
    24         if(dfn[y]==-1){
    25             tarjan(y);
    26             low[x]=min(low[x],low[y]);
    27         }
    28         else if(instac[y]!=0){
    29             low[x]=min(low[x],dfn[y]);
    30         }
    31     }
    32     if(dfn[x]==low[x]){
    33         tot++;
    34         int y;
    35         do{
    36             y=stac[top--];
    37             instac[y]=false;
    38             kin[tot].push_back(y);
    39             inkin[y]=tot;
    40         }while(y!=x);
    41     }
    42 }
    43 inline void calc(int x){
    44     if(son[x].size()==0){
    45         for(int i=cost[x];i<=M;i++) f[x][i]=val[x];
    46         return ;
    47     }
    48     for(int i=0;i<son[x].size();i++) calc(son[x][i]);
    49     
    50     for(int i=0;i<son[x].size();i++){
    51         int y=son[x][i];
    52         for(int tot=M;tot>=0;tot--){
    53             for(int j=0;j<=tot;j++){
    54                 f[x][tot]=max(f[x][tot],f[x][tot-j]+f[y][j]);
    55             }
    56         }
    57     }
    58     for(int i=M;i>=0;i--){
    59         if(i>=cost[x]) f[x][i]=f[x][i-cost[x]]+val[x];
    60         else f[x][i]=0;
    61     }
    62 }
    63 int main(){
    64     scanf("%d%d",&N,&M);
    65     for(int i=1;i<=N;i++) scanf("%d",&W[i]);
    66     for(int i=1;i<=N;i++) scanf("%d",&V[i]);
    67     for(int i=1;i<=N;i++){
    68         scanf("%d",&fa[i]);
    69         to[fa[i]].push_back(i);
    70     }
    71     memset(dfn,-1,sizeof(dfn));
    72     for(int i=1;i<=N;i++){
    73         if(dfn[i]==-1) tarjan(i);
    74     }
    75     for(int i=1;i<=tot;i++){
    76         int y=kin[i][0];
    77         if(kin[i].size()>=2){//形成一个环 ,取其中任意一点,缩环为点 
    78             val[y]=V[y]; cost[y]=W[y];
    79             son[0].push_back(y);
    80             for(int j=1;j<kin[i].size();j++){
    81                 val[y]+=V[kin[i][j]];
    82                 cost[y]+=W[kin[i][j]];
    83             }
    84         }
    85         else{//是一棵树上的某一点,直接复制 
    86             if(fa[y]==0) 
    87                 son[0].push_back(y);
    88             else{
    89                 int xx=inkin[fa[y]];
    90                 int yy=kin[xx][0];
    91                 son[yy].push_back(y);
    92             }
    93             val[y]=V[y]; cost[y]=W[y];
    94         }
    95     }
    96     val[0]=0; cost[0]=0; calc(0);
    97     printf("%d",f[0][M]);
    98     return 0;
    99 }
  • 相关阅读:
    php用正则表达式匹配URL的简单方法(亲测可行)
    MySQL中MyISAM与InnoDB区别及选择
    crontab定时任务语法及应用
    “购物狂欢节”如何应对“羊毛党”
    深入理解 Linux 的 RCU 机制
    白夜追凶 :手 Q 图片的显示和发送逻辑
    老司机教你如何优雅地完成一个小项目测试
    腾讯云分布式数据库可用性系统实践
    使用 Skeleton Screen 提升用户感知体验
    实战分享,教你蓝牙在小程序中的应用
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/5404421.html
Copyright © 2020-2023  润新知