• BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP


    BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP

    题意:

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

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

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

    分析:
    有环。

    考虑一个环内的贡献

    要么都取要么都不取

    缩个点跑树形背包就可以了

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 350
    int head[N],to[N<<1],nxt[N<<1],cnt,n;
    int m,f[N][600],cost[N],val[N],c[N],v[N],in[N];
    int st[N],top,ins[N],bl[N],scc,tot,vis[N];
    int dfn[N],low[N],from[N];
    inline void add(int u,int v){
        to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;from[cnt]=u;
    }
    void tarjan(int x){
        st[top++]=x;
        ins[x]=1;
        low[x]=dfn[x]=++tot;
        for(int i=head[x];i;i=nxt[i]){
            if(!dfn[to[i]]){
                tarjan(to[i]);
                low[x]=min(low[x],low[to[i]]);	
            }else if(ins[to[i]]){
                low[x]=min(low[x],dfn[to[i]]);	
            }
        }
        if(low[x]==dfn[x]){
            int t=st[--top];ins[t]=0;
            bl[t]=++scc;
            c[scc]=cost[t];
            v[scc]=val[t];
            while(t^x){
                t=st[--top];ins[t]=0;
                c[scc]+=cost[t];
                v[scc]+=val[t];
                bl[t]=scc;
            }
        }
    }
    void dfs(int x,int y){
        f[x][c[x]]=v[x];
        vis[x]=1;
        for(int i=head[x];i;i=nxt[i]){
            if(!vis[to[i]]){
                dfs(to[i],x);
                for(int j=m;j>=c[x];j--){
                    for(int k=m-j;k>=c[to[i]];k--){
                        f[x][j+k]=max(f[x][j+k],f[x][j]+f[to[i]][k]);
                    }
                }
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        int i,j,x,y;
        for(i=1;i<=n;i++)scanf("%d",&cost[i]);
        for(i=1;i<=n;i++)scanf("%d",&val[i]);
        for(i=1;i<=n;i++){
            scanf("%d",&x);
            if(x)
            	add(x,i);
        }
        for(i=1;i<=n;i++)if(!dfn[i])tarjan(i);
        int tmp=cnt;
        memset(head,0,sizeof(head));cnt=0;
        for(i=1;i<=tmp;i++){
            x=from[i],y=to[i];
            if(bl[x]!=bl[y]){
                add(bl[x],bl[y]);
                in[bl[y]]++;
            }
        }
        for(i=1;i<=scc;i++)if(!in[i]){
            add(scc+1,i);
        }
        dfs(scc+1,0);
        int ans=0;
        for(i=0;i<=m;i++)ans=max(ans,f[scc+1][i]);
        printf("%d
    ",ans);
    }
    /*
    3 10
    5 5 6
    2 3 4
    0 1 1 
    */
    
  • 相关阅读:
    删除链表中的一个节点
    链表系列面试题1
    线程的5种状态
    红黑树 实现
    Java的SPI机制浅析与简单示例
    socket原理
    rabbitmq简单介绍
    MongoTemplate操作mongodb
    RJava配置
    浅析前后台分离
  • 原文地址:https://www.cnblogs.com/suika/p/8511857.html
Copyright © 2020-2023  润新知