码迷,mamicode.com
首页 > 其他好文 > 详细

luogu P2515 [HAOI2010]软件安装 |Tarjan+树上背包

时间:2019-11-13 21:55:39      阅读:61      评论:0      收藏:0      [点我收藏+]

标签:stream   cstring   min   void   软件   iostream   现在   整数   --   

题目描述

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

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

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

输入格式

第1行:N,M(0≤N≤100,0≤M≤500)

第2行:W_1,W_2, ... W_i, ..., W_n

第3行:V_1, V_2, ..., V_i, ..., V_n

第4行:D_1, D_2, ..., D_i, ..., D_n

输出格式

一个整数,代表最大价值


先把图缩点,变成树

然后做树上背包

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=505,M=10*N;
int nxt[M],head[N],go[M],tot;
inline void add(int u,int v){
    nxt[++tot]=head[u];head[u]=tot;go[tot]=v;
}
int cost[N],val[N],d[N],f[N][N];
int dfn[N],low[N],co[N],st[N],col,num,top;
int c[N],va[N];
inline void Tarjan(int u){
    dfn[u]=low[u]=++num;
    st[++top]=u;
    for(int e=head[u];e;e=nxt[e]){
        int v=go[e];
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!co[v])low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        co[u]=++col;
        while(st[top]!=u){ 
            co[st[top]]=col;
            --top;
        }
        --top;
    }
}
int in[N];
int n,m;
inline void dfs(int u){
    for(int i=c[u];i<=m;i++)f[u][i]=va[u];
    for(int i=head[u];i;i=nxt[i]){
        int v=go[i];
        dfs(v);
        for(int j=m-c[u];j>=0;j--)
        for(int q=0;q<=j;q++)
        f[u][j+c[u]]=max(f[u][j+c[u]],f[u][j+c[u]-q]+f[v][q]);
    }
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%lld",&cost[i]);
    for(int i=1;i<=n;i++)scanf("%lld",&val[i]);
    for(int i=1;i<=n;i++){
        scanf("%lld",&d[i]);
        if(d[i])add(d[i],i);
    }
    for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
    memset(nxt,0,sizeof(nxt)),memset(head,0,sizeof(head)),memset(go,0,sizeof(go)),tot=0;
    for(int i=1;i<=n;i++){
        c[co[i]]+=cost[i];
        va[co[i]]+=val[i];
        if(d[i]!=0&&co[i]!=co[d[i]])
        add(co[d[i]],co[i]),in[co[i]]++;
    }
    int s=col+1;
    for(int i=1;i<=col;i++)if(!in[i])add(s,i);
    c[s]=0,va[s]=0; dfs(s);
    cout<<f[s][m]<<endl;
    return 0;
}

luogu P2515 [HAOI2010]软件安装 |Tarjan+树上背包

标签:stream   cstring   min   void   软件   iostream   现在   整数   --   

原文地址:https://www.cnblogs.com/naruto-mzx/p/11853273.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!