BZOJ2427: [HAOI2010]软件安装

【传送门:BZOJ2427


简要题意:

  给出n个软件,共有m的空间,每个软件只能安装一次,每个软件安装后占用w[i]的空间,得到v[i]的价值

  有些软件至多有一个它们的父软件,相当于父软件被子软件依赖,只有当父软件被安装,才能安装当前的软件

  求出最大价值


题解:

  如果x为y的父软件,则x连向y

  很显然会出现多个软件互相依赖的情况,就是成环了

  那么就用强联通缩点,然后将空间和费用累加,作为新点

  然后如果没有父软件的点,设一个虚根0,然后0连向这些点

  设f[i][j]为在i点时使用j的空间的最大价值

  然后在树形DP的时候,在继承的时候保证父节点被选中才能选子节点就可以了


参考代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
int w[110],v[110];
struct node
{
    int x,y,next;
}a[110],b[110];int len,last[110];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
int dfn[110],low[110],id;
int belong[110],s;
int sta[110],tp;
bool bo[110];
int V[110],W[110];
void dfs(int x)
{
    dfn[x]=low[x]=++id;
    sta[++tp]=x;bo[x]=true;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(dfn[y]==-1)
        {
            dfs(y);
            low[x]=min(low[x],low[y]);
        }
        else
        {
            if(bo[y]==true) low[x]=min(low[x],dfn[y]);
        }
    }
    if(low[x]==dfn[x])
    {
        s++;int i;
        do
        {
            i=sta[tp--];
            belong[i]=s;
            bo[i]=false;
        }while(i!=x);
    }
}
int f[110][510];
int m;
void treedp(int x)
{
    f[x][W[x]]=V[x];
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        treedp(y);
        for(int i=m;i>W[x];i--)
        {
            for(int j=0;j<=i-W[x];j++)
            {
                if(i>=j) f[x][i]=max(f[x][i],f[y][j]+f[x][i-j]);
            }
        }
    }
}
int d[110],ru[110];
int main()
{int n;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    for(int i=1;i<=n;i++) scanf("%d",&v[i]);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&d[i]);
        ins(d[i],i);
    }
    memset(bo,false,sizeof(bo));
    id=s=tp=0;
    memset(V,0,sizeof(V));
    memset(W,0,sizeof(W));
    memset(dfn,-1,sizeof(dfn));
    for(int i=1;i<=n;i++) if(dfn[i]==-1) dfs(i);
    len=0;memset(last,0,sizeof(last));
    memset(ru,0,sizeof(ru));
    for(int i=1;i<=n;i++)
    {
        int x=d[i],y=i;
        V[belong[i]]+=v[i];W[belong[i]]+=w[i];
        if(belong[x]!=belong[y])
        {
            ins(belong[x],belong[y]);
            ru[belong[y]]++;
        }
    }
    for(int i=1;i<=s;i++) if(ru[i]==0) ins(0,i);
    treedp(0);
    printf("%d\n",f[0][m]);
    return 0;
}
posted @ 2018-03-25 14:40  Star_Feel  阅读(153)  评论(0编辑  收藏  举报