[HAOI2010]软件安装

题目:洛谷P2515、BZOJ2427、codevs1866。

题目大意:有n个物品,每个物品有重量和价值,且只能选一次。每个物品可能有一个依赖物品,选了该物品必须先选择它的依赖物品(可能会有环)。给出背包的容量,求可以装物品的最大价值。

解题思路:首先强连通分量缩点,然后树形dp求01背包即可。

C++ Code:

#include<bits/stdc++.h>
int n,m,fa[105],w[105],v[105],dfn[105],low[105],idx=0,ys[105],ltfl=0,dad[105];
std::vector<int>a[105];
int f[105][505],W[105],V[105],ans=0,cnt=0,head[105];
bool instack[105];
std::stack<int>s;
inline int debian(){
    int c=getchar();
    for(;!isdigit(c);c=getchar());
    int d=0;
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^'0');
    return d;
}
struct edge{
    int to,nxt;
}e[66667];
void tarjan(int now){
    dfn[now]=low[now]=++idx;
    s.push(now);
    instack[now]=true;
    if(fa[now]){
        if(dfn[fa[now]]){
            if(instack[fa[now]]&&low[now]>dfn[fa[now]])
            low[now]=dfn[fa[now]];
        }else{
            tarjan(fa[now]);
            if(low[now]>low[fa[now]])low[now]=low[fa[now]];
        }
    }
    if(low[now]==dfn[now]){
        ++ltfl;
        int p;
        do{
            p=s.top();
            s.pop();
            instack[p]=false;
            a[ltfl].push_back(p);
            ys[p]=ltfl;
            W[ltfl]+=w[p];
            V[ltfl]+=v[p];
        }while(p!=now);
    }
}
void dp(int now){
    //fprintf(stderr,"233  %d  233\n",now);
    for(int i=W[now];i<=m;++i)
    f[now][i]=V[now];
    for(int i=head[now];i;i=e[i].nxt){
        dp(e[i].to);
        for(int j=m;j>=W[now];--j){
            for(int k=0;k<=m;++k){
                if(k+j>m)break;
                if(f[now][j+k]<f[now][j]+f[e[i].to][k])f[now][j+k]=f[now][j]+f[e[i].to][k];
            }
        }
    }
}
int main(){
    n=debian(),m=debian();
    memset(fa,-1,sizeof fa);
    for(int i=1;i<=n;++i)w[i]=debian();
    for(int i=1;i<=n;++i)v[i]=debian();
    for(int i=1;i<=n;++i)fa[i]=debian();
    memset(dfn,0,sizeof dfn);
    memset(W,0,sizeof W);
    memset(V,0,sizeof V);
    for(int i=1;i<=n;++i)
    if(!dfn[i])tarjan(i);
    //fprintf(stderr,"%d\n",ltfl);
    for(int i=1;i<=n;++i){
        if(fa[i]==0||a[ys[i]].size()>1)dad[ys[i]]=0;else
        dad[ys[i]]=ys[fa[i]];
    }
    memset(f,0,sizeof f);
    memset(head,0,sizeof head);
    //for(int i=1;i<=ltfl;++i)fprintf(stderr,"%d: %d %d %d\n",i,dad[i],W[i],V[i]);
    for(int i=1;i<=ltfl;++i){
        e[++cnt]=(edge){i,head[dad[i]]};
        head[dad[i]]=cnt;
    }
    dp(0);
    for(int i=0;i<=m;++i)
    if(f[0][i]>ans)ans=f[0][i];
    //for(int i=0;i<=ltfl;++i,putchar('\n'))
    //for(int j=0;j<=m;++j)printf("%d ",f[i][j]);
    return!printf("%d\n",ans);
}

 

posted @ 2018-03-22 20:17  Mrsrz  阅读(146)  评论(0编辑  收藏  举报