luogu P2515 [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
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1007;

inline int read() {
    int x=0,f=1;
    char c=getchar() ;
    while(c<'0'||c>'9'){ if(c=='-')f=-1;c=getchar();};
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
    return x*f;
}
int w[maxn],v[maxn],n,m;
struct node {
    int v,next;
}edge[maxn*5],E[maxn*10];
int num=0,N=0,H[maxn*2],head[maxn];
inline void add_edge(int u,int v) {
    edge[++num].v=v;edge[num].next=head[u];head[u]=num;
}
inline void ADD(int u,int v) {
    E[++N].v=v;E[N].next=H[u];H[u]=N;
}
int dfn[maxn],low[maxn],color[maxn],color_cnt=0,stack[maxn],vul[maxn],wul[maxn];
bool vis[maxn];int top;
void tarjan(int x) {
    dfn[x]=low[x]=++num;
    vis[x]=1;stack[++top]=x;
    for(int i=head[x];i;i=edge[i].next) {
        int v=edge[i].v;
        if(!dfn[v]) {
            tarjan(v);
            low[x]=std::min(low[x],low[v]);
        }
        else if(vis[v]) low[x]=min(low[x],dfn[v]);
    }
    if(low[x]==dfn[x]) {
        color_cnt++;
        while(stack[top+1]!=x) {
            vis[stack[top]]=0;
            color[stack[top]]=color_cnt;
            vul[color_cnt]+=v[stack[top]];
            wul[color_cnt]+=w[stack[top]];top--;
        }
    }
}
int dp[maxn*2][maxn*5];
void dfs(int x) {
    for(int i=wul[x];i<=m;++i) dp[x][i]=vul[x];
    for(int i=H[x];i;i=E[i].next) {
        int vv=E[i].v;
        dfs(vv);
        for(int j=m-wul[x];j>=0;j--) 
            for(int k=0;k<=j;k++) {
                dp[x][j+wul[x]]=max(dp[x][j+wul[x]],dp[x][j+wul[x]-k]+dp[vv][k]);
            }
    }
    //for(int i=m;i>=0;i--) 
        //if(w[i]<=i)dp[x][i]=v[x];
        //else dp[x][i]=0;
}
bool rd[maxn*2];
int main() {
    n=read(),m=read();
    for(int i=1;i<=n;++i) w[i]=read();
    for(int i=1;i<=n;++i) v[i]=read();
    for(int a,i=1;i<=n;++i) {
        a=read();
        if(a) add_edge(a,i);
    }num=0;
    //for(int i=1;i<=n;++i) {
    //    color[i]=i;
    //}
    for(int i=1;i<=n;++i) 
        if(!dfn[i])tarjan(i);
    for(int i=1;i<=n;++i) 
        for(int j=head[i];j;j=edge[j].next) {
            int vv=edge[j].v;
            if(color[i]!=color[vv]) {
                ADD(color[i],color[vv]);
                rd[color[vv]]=1;
            }
        }
    for(int i=1;i<=n;++i) {
        if(!rd[color[i]])ADD(0,color[i]);
    }
    dfs(0);
    printf("%d
",dp[0][m]);
    return 0;
}
原文地址:https://www.cnblogs.com/sssy/p/8010506.html