zoukankan      html  css  js  c++  java
  • 【BZOJ2427】【HAOI2010】软件安装

    原题:

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

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

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

    n<=100,m<=500,wi<=m,vi<=1000

    解法很简单,注意到软件可能相互依赖,所以tarjan缩环然后树上dp

    这题我卡了一晚上,总是90分

    然后翻博客

    两年前我是这样写的:照着AC代码瞎改一通,过了但是没想明白为什么

    两年后我又做了同样的事情

    对比两份代码发现

    写法一:每个节点开始只有f[w[i]]=v[i]其余为-oo,然后f[father[x]][i]=max(f[father[x]][i],f[father[x]][i-j]+f[x][j])

    写法二:开始所有f[i][j]为0,然后f[father[x]][i]=max(f[father[x]][i],f[father[x]][i-j]+f[x][j]),最后

    for(int i=m;i>=w[x];--i) f[x][i]=f[x][i-w[x]]+v[x];

    for(int i=0;i<w[x];++i) f[x][i]=0;

    写法一90写法二100

    继续研究发现,把写法一从f[i][w[i]]=v[i]改成f[i][j]=v[i](w[i]<=j<=m)就过了

    要到数据,把两种初始化方法打表出来观察

    终于发现!

    缩点之后点的质量会大于包容量

    然后越界了

    代码:(因为一开始没有意识到要用拓扑排序或重新建图所以写得有点屎):

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstdio>
     5 #include<algorithm>
     6 using namespace std;
     7 int rd(){int z=0,mk=1;  char ch=getchar();
     8     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
     9     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    10     return z*mk;
    11 }
    12 struct edg{int y,nxt;}e[210];  int lk[110],ltp=0;
    13 void ist(int x,int y){
    14     e[++ltp]=(edg){y,lk[x]};  lk[x]=ltp;
    15     //e[++ltp]=(edg){x,lk[y]};  lk[y]=ltp;
    16 }
    17 int n,m,a[110],b[110];  int fth[110];
    18 int dfn[110],low[110],dft=0;
    19 int q[110],hd=0;
    20 int cid[110],ctp=0;
    21 int c[110],d[110];
    22 bool g[110][110];
    23 int f[110][51000];  //!!!
    24 bool vstd[110];
    25 int nd[110];
    26 int tth[110];
    27 void tj(int x,int y){
    28     dfn[x]=++dft;  low[x]=dfn[x];
    29     q[++hd]=x;
    30     for(int i=lk[x];i;i=e[i].nxt){//if(e[i].y!=y){
    31         if(!dfn[e[i].y]){
    32             tj(e[i].y,x);
    33             low[x]=min(low[x],low[e[i].y]);
    34         }
    35         else if(!cid[e[i].y])
    36             low[x]=min(low[x],low[e[i].y]);
    37     }
    38     if(dfn[x]==low[x]){
    39         ++ctp;
    40         int tmp=0;
    41         for(;tmp!=x && hd;tmp=q[hd--]){
    42             cid[q[hd]]=ctp;
    43             c[ctp]+=a[q[hd]];
    44             d[ctp]+=b[q[hd]];
    45         }
    46     }
    47 }
    48 void dfs(int x,int y){
    49     vstd[x]=true;
    50     f[x][c[x]]=d[x];
    51     for(int i=lk[x];i;i=e[i].nxt)if(e[i].y!=y)
    52         dfs(e[i].y,x);
    53     for(int j=m;j>=0;--j)for(int k=0;j-k>=0;++k)
    54         f[y][j]=max(f[y][j],f[y][j-k]+f[x][k]);
    55 }
    56 void prvs(){
    57     ltp=0;
    58     for(int i=1;i<=n;++i)  lk[i]=0;
    59     for(int i=1;i<=n;++i)  dfn[i]=0;
    60     hd=0;  ctp=0;
    61     for(int i=1;i<=n;++i)  c[i]=0,d[i]=0;
    62     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)  g[i][j]=false;
    63     for(int i=0;i<=n;++i)for(int j=0;j<=m;++j)  f[i][j]=-1000000007;
    64     //注意背包初值
    65     for(int i=1;i<=n;++i)  vstd[i]=false;
    66     for(int i=1;i<=n;++i)  nd[i]=0;
    67 }
    68 int main(){
    69     //freopen("ddd.in","r",stdin);
    70     cin>>n>>m;  prvs();
    71     for(int i=1;i<=n;++i)  a[i]=rd();
    72     for(int i=1;i<=n;++i)  b[i]=rd();
    73     for(int i=1;i<=n;++i){
    74         fth[i]=rd();
    75         if(fth[i])  ist(i,fth[i]);
    76     }
    77     for(int i=1;i<=n;++i)if(!dfn[i])
    78         tj(i,0);
    79     for(int i=1;i<=n;++i)if(cid[i]!=cid[fth[i]])  tth[cid[i]]=cid[fth[i]];
    80     n=ctp;
    81     for(int i=1;i<=n;++i)  fth[i]=tth[i];
    82     for(int i=1;i<=n;++i)if(fth[i])  ++nd[fth[i]];  //注意是有根树,只能用拓扑排序dp
    83     hd=0;
    84     for(int i=1;i<=n;++i)if(!nd[i])  q[++hd]=i;
    85     f[0][0]=0;  //注意0节点初值
    86     for(int i=1;i<=n;++i)  f[i][c[i]]=d[i];
    87     //注意初始化的位置,不能在下面
    88     for(int k=1;k<=hd;++k){
    89         //f[q[k]][c[q[k]]]=d[q[k]];
    90         for(int i=m;i>=0;--i)for(int j=0;i-j>=0;++j)
    91             f[fth[q[k]]][i]=max(f[fth[q[k]]][i],f[fth[q[k]]][i-j]+f[q[k]][j]);
    92         --nd[fth[q[k]]];
    93         if(!nd[fth[q[k]]])  q[++hd]=fth[q[k]];
    94     }
    95     int ans=0;
    96     for(int i=0;i<=m;++i)  ans=max(ans,f[0][i]);
    97     cout<<ans<<endl;
    98     return 0;
    99 }
    View Code
  • 相关阅读:
    JVM探秘1--JVM内存运行时区域划分
    skywalking学习之路---skywalking环境从零搭建部署
    ES6学习笔记之解构赋值
    ES6学习笔记之Symbol
    ES6学习笔记之块级作用域
    Vue开发警告[Vue warn]: Avoid replacing instance root $data. Use nested data properties instead.
    JavaScript实现归并排序
    Vue-cli3.x在开发环境中(router采用 history模式)出现Failed to resolve async component default: Error: Loading chunk {/d} failed.或者Uncaught SyntaxError: Unexpected token <错误
    vue-cli3.x中使用axios发送请求,配合webpack中的devServer编写本地mock数据接口(get/post/put/delete)
    uni-app开发微信小程序引入UI组件库(Vant-weapp)步骤
  • 原文地址:https://www.cnblogs.com/cdcq/p/11735279.html
Copyright © 2011-2022 走看看