zoukankan      html  css  js  c++  java
  • BZOJ2427:[HAOI2010]软件安装——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2427

    https://www.luogu.org/problemnew/show/P2515

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

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

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

    dp简单题,然而因为数组开小了debug了两天???

    (不过同时让我de出了一些题解的bug)

    如果从属关系为环的话,显然其中一个选则全环都得选,于是tarjan缩点,变成了森林。

    建虚点连接每个森林,剩余的就是树上背包了,与HDU1561:The more, The Better相同,但是因为n很小所以选择了O(n^2*m)的做法。

    同时与那道题不同的是,因为体积可以为0,所以可能会出现有后效性的情况,特判之。

    #include<map>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=105;
    const int M=505;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int to,nxt;
    }e[N*2];
    stack<int>q;
    bool inq[N];
    int pre[N],d[N][N];
    int cnt,head[N],n,m,dp[N][M];
    int val[N],w[N],weight[N],b[N];
    int dfn[N],low[N],to[N],indeg[N],t,l;
    inline void add(int u,int v){
        e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
    }
    void dfs(int u){
        for(int i=b[u];i<=m;i++)dp[u][i]=w[u];
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            dfs(v);
            for(int j=m;j>=b[u];j--){
                int tmp=dp[u][j];
                for(int k=b[u];k<=j-b[v];k++){
                    if(k!=j)dp[u][j]=max(dp[u][j],dp[u][k]+dp[v][j-k]);
                    else dp[u][j]=max(dp[u][j],tmp+dp[v][j-k]);
                }
            }
        }
    }
    void tarjan(int u){
        int v;
        dfn[u]=low[u]=++t;
        q.push(u);inq[u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            v=e[i].to;
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }else if(inq[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u]){
            l++;
            do{
                v=q.top();q.pop();
                inq[v]=0;to[v]=l;
                w[l]+=val[v];b[l]+=weight[v];
            }while(v!=u);
        }
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++)weight[i]=read();
        for(int i=1;i<=n;i++)val[i]=read();
        for(int v=1;v<=n;v++){
            pre[v]=read();
            if(pre[v])add(pre[v],v);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])tarjan(i);
        memset(head,0,sizeof(head));cnt=0;
        for(int i=1;i<=n;i++){
            int u=to[pre[i]],v=to[i];
            if(!pre[i]||u==v)continue;
            if(!d[u][v]){
                d[u][v]=1;add(u,v);indeg[v]++;
            }
        }
        int rt=l+1;
        for(int i=1;i<=l;i++)
            if(!indeg[i])add(rt,i);
        dfs(rt);
        printf("%d
    ",dp[rt][m]);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    905. Sort Array By Parity
    arts-week9
    521. Longest Uncommon Subsequence I
    arts-week8
    学习linux/unix编程方法的建议,学习Linux的四个步骤(转)
    对Linux内核tty设备的一点理解(转)
    ARM微处理器中支持字节、半字、字三种数据类型,地址的低两位为0是啥意思?
    c语言中 char* 和 unsigned char* 的区别浅析(转)
    命名空间的定义与使用(转)
    每日一句古文(转)
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8921833.html
Copyright © 2011-2022 走看看