BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP

BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP

题意:

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

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

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

分析:
有环。

考虑一个环内的贡献

要么都取要么都不取

缩个点跑树形背包就可以了

 

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 350
int head[N],to[N<<1],nxt[N<<1],cnt,n;
int m,f[N][600],cost[N],val[N],c[N],v[N],in[N];
int st[N],top,ins[N],bl[N],scc,tot,vis[N];
int dfn[N],low[N],from[N];
inline void add(int u,int v){
    to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;from[cnt]=u;
}
void tarjan(int x){
    st[top++]=x;
    ins[x]=1;
    low[x]=dfn[x]=++tot;
    for(int i=head[x];i;i=nxt[i]){
        if(!dfn[to[i]]){
            tarjan(to[i]);
            low[x]=min(low[x],low[to[i]]);	
        }else if(ins[to[i]]){
            low[x]=min(low[x],dfn[to[i]]);	
        }
    }
    if(low[x]==dfn[x]){
        int t=st[--top];ins[t]=0;
        bl[t]=++scc;
        c[scc]=cost[t];
        v[scc]=val[t];
        while(t^x){
            t=st[--top];ins[t]=0;
            c[scc]+=cost[t];
            v[scc]+=val[t];
            bl[t]=scc;
        }
    }
}
void dfs(int x,int y){
    f[x][c[x]]=v[x];
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        if(!vis[to[i]]){
            dfs(to[i],x);
            for(int j=m;j>=c[x];j--){
                for(int k=m-j;k>=c[to[i]];k--){
                    f[x][j+k]=max(f[x][j+k],f[x][j]+f[to[i]][k]);
                }
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    int i,j,x,y;
    for(i=1;i<=n;i++)scanf("%d",&cost[i]);
    for(i=1;i<=n;i++)scanf("%d",&val[i]);
    for(i=1;i<=n;i++){
        scanf("%d",&x);
        if(x)
        	add(x,i);
    }
    for(i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    int tmp=cnt;
    memset(head,0,sizeof(head));cnt=0;
    for(i=1;i<=tmp;i++){
        x=from[i],y=to[i];
        if(bl[x]!=bl[y]){
            add(bl[x],bl[y]);
            in[bl[y]]++;
        }
    }
    for(i=1;i<=scc;i++)if(!in[i]){
        add(scc+1,i);
    }
    dfs(scc+1,0);
    int ans=0;
    for(i=0;i<=m;i++)ans=max(ans,f[scc+1][i]);
    printf("%d\n",ans);
}
/*
3 10
5 5 6
2 3 4
0 1 1 
*/

 

posted @ 2018-03-05 22:53  fcwww  阅读(130)  评论(0编辑  收藏  举报