• [HAOI2010]软件安装(Tarjan,树形dp)


    [HAOI2010]软件安装

    题目描述

    现在我们的手头有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 )

    输出格式:

    一个整数,代表最大价值

    输入输出样例

    输入样例#1:

    3 10
    5 5 6
    2 3 4
    0 1 1

    输出样例#1:

    5

    被看错题和脑抽卡了一晚上......
    就是个有依赖的树形背包,但是没看到间接依赖也不能对答案造成贡献,以为像是没有上司的舞会那样的dp。
    先将原图缩点,要选的话至少要选一个强连通分量,否则不能对答案造成贡献,缩完点之后就是个DAG了,直接跑树形背包就完了。(我居然连树形背包的板子都不记得了)

    #include<bits/stdc++.h>
    using namespace std;
    int read(){
        int x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*w;
    }
    const int N=110,M=510;
    int n,m,cnt,top,visnum,num,ans;
    int w[N],c[N],d[N],sumw[N],sumc[N],head[N];
    int dfn[N],low[N],s[N],in[N],belong[N],du[N];
    int dp[N][M];
    struct node{
        int to,next;
    }edge[2*N];
    void add(int x,int y){
        cnt++;edge[cnt].to=y;edge[cnt].next=head[x];head[x]=cnt;
    }
    queue<int>q;
    void tarjan(int k){
        dfn[k]=low[k]=++visnum;
        s[++top]=k;in[k]=1;
        for(int i=head[k];i;i=edge[i].next){
            int v=edge[i].to;
            if(!dfn[v]){
                tarjan(v);low[k]=min(low[k],low[v]);
            }
            else if(in[v])low[k]=min(low[k],dfn[v]);
        }
        if(dfn[k]==low[k]){
            num++;int v=0;
            while(v!=k){
                v=s[top--];in[v]=0;
                belong[v]=num;sumw[num]+=w[v];sumc[num]+=c[v];
            }
        }
    }
    void DP(int k){
        for(int i=head[k];i;i=edge[i].next){
            int v=edge[i].to;DP(v);
            for(int j=m;j>=0;j--)
                for(int l=j;l>=0;l--)
                    dp[k][j]=max(dp[k][j],dp[k][j-l]+dp[v][l]);
        }
        for(int i=m;i>=0;i--)
            if(i>=sumw[k])
                dp[k][i]=dp[k][i-sumw[k]]+sumc[k];
            else dp[k][i]=0;
    }
    int main(){
        n=read();m=read();
        for(int i=1;i<=n;i++)w[i]=read();
        for(int i=1;i<=n;i++)c[i]=read();
        for(int i=1;i<=n;i++){
            d[i]=read();if(d[i])add(d[i],i);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])tarjan(i);
        cnt=top=0;memset(head,0,sizeof(head));
        for(int i=1;i<=n;i++){
            if(!d[i]||belong[i]==belong[d[i]])continue;
            add(belong[d[i]],belong[i]);du[belong[i]]++;
        }
        for(int i=1;i<=num;i++)if(!du[i])add(0,i);
        DP(0);for(int i=0;i<=m;i++)ans=max(ans,max(dp[0][i],dp[0][i]));
        printf("%d",ans);return 0;
    }
    
  • 相关阅读:
    Java变量相关
    centos 7安装Docker
    字符串匹配的KMP算法
    [转]关于”算法工程师/机器学习工程师”的笔试和面试总结
    希腊字母与拉丁字母的对应
    决策树和基于决策树的集成方法(DT,RF,GBDT,XGB)复习总结
    机器学习总结
    bat批处理的注释语句
    Python中使用pickle持久化对象
    怎样用通俗的语言解释REST,以及RESTful?
  • 原文地址:https://www.cnblogs.com/lsgjcya/p/9757143.html
Copyright © 2020-2023  润新知