[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;
}
posted @ 2018-10-08 21:03  Frozen_Heart  阅读(218)  评论(0编辑  收藏  举报