洛谷 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

 思路:tarjin缩点+树形DP

错因:MLE

#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 10001
#define M 2501
using namespace std;
map<int,int>ma[N];
int n,m,K;
int tot,top;
int tim,sum,sumcol;
int col[N],kk[N],vval[N];
int to[N],net[N],head[N];
int k[N],val[N],f[N][M],dp[M];
int dad[N],lchild[N],rchild[N];
int vis[N],dis[N],low[N],stack[N],visstack[N];
void add(int u,int v){
    to[++tot]=v;net[tot]=head[u];head[u]=tot;
}
void tarjin(int now){
    dis[now]=low[now]=++tim;
    vis[now]=1;
    stack[++top]=now;
    visstack[now]=1;
    for(int i=head[now];i;i=net[i])
        if(visstack[to[i]])
            low[now]=min(low[now],dis[to[i]]);
        else if(!vis[to[i]]){
            tarjin(to[i]);
            low[now]=min(low[now],low[to[i]]);
        }
    if(low[now]==dis[now]){
        sumcol++;
        col[now]=sumcol;
        while(stack[top]!=now){
            col[stack[top]]=sumcol;
            visstack[stack[top]]=0;
            top--;
        }
        visstack[now]=0;
        top--;
    }
}
int dfs(int i,int j){
    if(i>n||i<1||j>K||j<1)    return 0;
    if(f[i][j])    return f[i][j];
    for(int kkk=0;kkk<=j-kk[i];kkk++)
        f[i][j]=max(f[i][j],dfs(lchild[i],kkk)+dfs(rchild[i],j-kkk-kk[i])+vval[i]);
    f[i][j]=max(f[i][j],dfs(rchild[i],j));
    return f[i][j];
}
int main(){
    scanf("%d%d",&n,&K);
    for(int i=1;i<=n;i++)    scanf("%d",&k[i]);
    for(int i=1;i<=n;i++)    scanf("%d",&val[i]);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        if(x!=0)    add(x,i);
    }
    for(int i=1;i<=n;i++)
        if(!vis[i])    tarjin(i);
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=net[j])
            if(col[i]!=col[to[j]])
                if(ma[col[i]].find(col[to[j]])==ma[col[i]].end()){
                    ma[col[i]][col[to[j]]]=1;
                    dad[col[to[j]]]=col[i];
                }
    for(int i=1;i<=sumcol;i++){
        int fa=dad[i];
        if(!lchild[fa])    lchild[fa]=i;
        else{
            fa=lchild[fa];
            while(rchild[fa])    fa=rchild[fa];
            rchild[fa]=i;
        }    
    }
    for(int i=1;i<=n;i++){
        kk[col[i]]+=k[i];
        vval[col[i]]+=val[i];
    }
    cout<<dfs(lchild[0],K);
}

 

posted @ 2017-09-18 15:10  一蓑烟雨任生平  阅读(200)  评论(0编辑  收藏  举报