zoukankan      html  css  js  c++  java
  • [BZOJ2427][HAOI2010]软件安装(Tarjan+DP)

    2427: [HAOI2010]软件安装

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1987  Solved: 791
    [Submit][Status][Discuss]

    Description

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

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

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

    Input

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

    Output

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

    Sample Input

    3 10
    5 5 6
    2 3 4
    0 1 1

    Sample Output

    5

    HINT

    Source

    这么简单的题竟然做了三个小时?

    环套树DP,为了方便直接Tarjan缩点然后跑树形DP即可。至于多叉树转二叉树这个方法完全不需要用上,直接做树上背包即可。

    注意:除非卡常时,不要再用~i表示i>=0了,这样无法处理i<0的情况。

    坚决避免低级错误!

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 #define For(i,x) for (int i=h[x]; i; i=nxt[i])
     6 using namespace std;
     7 
     8 const int N=2100;
     9 int n,m,scc,cnt,tim,top,h[N<<1],ind[N],w[N],v[N],d[N],wei[N],val[N];
    10 int bel[N],dp[N][N],stk[N],inq[N],dfn[N],low[N],to[N<<2],nxt[N<<2];
    11 
    12 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    13 
    14 void tarjan(int x){
    15     low[x]=dfn[x]=++tim; inq[x]=1; stk[++top]=x;
    16     For(i,x){
    17         int k=to[i];
    18         if (!dfn[k]) tarjan(k),low[x]=min(low[x],low[k]);
    19             else if (inq[k]) low[x]=min(low[x],dfn[k]);
    20     }
    21     if (dfn[x]==low[x]){
    22         int t; scc++;
    23         do{ t=stk[top--]; inq[t]=0; bel[t]=scc; }while (t!=x);
    24     }
    25 }
    26 
    27 void dfs(int x){
    28     rep(i,wei[x],m) dp[x][i]=val[x];
    29     For(i,x){
    30         int k=to[i]; dfs(k);
    31         for (int j=m-wei[x]; j>=0; j--)
    32             rep(q,0,j)
    33                 dp[x][j+wei[x]]=max(dp[x][j+wei[x]],dp[x][j+wei[x]-q]+dp[k][q]);
    34     }
    35 }
    36 
    37 int main(){
    38     scanf("%d%d",&n,&m); scc=n;
    39     rep(i,1,n) scanf("%d",&w[i]);
    40     rep(i,1,n) scanf("%d",&v[i]);
    41     rep(i,1,n) { scanf("%d",&d[i]); if (d[i]) add(d[i],i); }
    42     rep(i,1,n) if (!dfn[i]) tarjan(i);
    43     rep(i,1,n){
    44         wei[bel[i]]+=w[i]; val[bel[i]]+=v[i];
    45         if (bel[i]!=bel[d[i]] && d[i]) add(bel[d[i]],bel[i]),ind[bel[i]]++;
    46     }
    47     rep(i,n+1,scc) if (!ind[i]) add(scc+1,i);
    48     dfs(scc+1); printf("%d
    ",dp[scc+1][m]);
    49     return 0;
    50 }
  • 相关阅读:
    TreeMap Red-Black tree
    Java实现生产者消费者问题与读者写者问题
    一个对象占用多大内存
    MySQL索引背后的数据结构及算法原理
    Java并发编程与技术内幕:线程池深入理解
    Java Spring 中你不知道的注入方式
    面试中的排序算法总结
    JAVA反射
    StringBuilder与StringBuffer的区别
    Java多线程总结【转】
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8543064.html
Copyright © 2011-2022 走看看