• [HAOI2010][BZOJ2427] 软件安装|tarjan|树型dp


    2427: [HAOI2010]软件安装

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 463  Solved: 194
    [Submit][Status][Discuss]

    Description

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

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

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

    Input

    第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 )

    Output

    一个整数,代表最大价值。

    Sample Input

    3 10
    5 5 6
    2 3 4
    0 1 1

    Sample Output

    5

    HINT

     

    Source

     
    读完题思路很清晰:先缩环,然后树型dp,大概就是个背包。
    首先f[i][j]=max(f[i][j],f[list[i]][k]+f[i][j-k]),j∈[0,w[i]],k∈[0,j]。然后f[i][j]=f[i][j-w[i]]+v[i],j∈[w[i],m](因为选子树必选i)。
     
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int next0[205],list0[205],head0[105],next[205],list[205],head[105];
    int n,m,top,top0,t,cnt,sum;
    bool vis[105],inset[105];
    int dfn[105],low[105],stack[105],belong[105],w[105],w0[105],v[105],v0[105];
    int f[105][505];
    inline int read()
    {
        int a=0,f=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*f;
    }
    inline void insert0(int x,int y)
    {
        next0[++top0]=head0[x];
        head0[x]=top0;
        list0[top0]=y;
    }
    inline void insert(int x,int y)
    {
        vis[y]=1;
        next[++top]=head[x];
        head[x]=top;
        list[top]=y;
    }
    void dfs(int x)
    {
        dfn[x]=low[x]=++sum;
        stack[++t]=x;
        inset[x]=1;
        for (int i=head0[x];i;i=next0[i])
        {
            if (!dfn[list0[i]])
            {
                dfs(list0[i]);
                low[x]=min(low[x],low[list0[i]]);
            }
            if (inset[list0[i]]) low[x]=min(low[x],dfn[list0[i]]);
        }
        int i=-1;
        if (dfn[x]==low[x])
        {
            cnt++;
            while (i!=x)
            {
                i=stack[t--];
                inset[i]=0;
                belong[i]=cnt;
                w[cnt]+=w0[i];
                v[cnt]+=v0[i];
            }
        }
    }
    inline void tarjan()
    {
        for (int i=1;i<=n;i++) if (!dfn[i]) dfs(i);
    }
    inline void rebuild()
    {
        for (int i=1;i<=n;i++)
            for (int j=head0[i];j;j=next0[j])
                if (belong[list0[j]]!=belong[i])
                    insert(belong[i],belong[list0[j]]);
    }
    void dp(int x)
    {
        for (int i=head[x];i;i=next[i])
        {
            dp(list[i]);
            for (int j=m-w[x];j>=0;j--)
                for (int k=0;k<=j;k++)
                    f[x][j]=max(f[x][j],f[x][k]+f[list[i]][j-k]);
        }
        for (int j=m;j>=0;j--)
            if (j>=w[x]) f[x][j]=f[x][j-w[x]]+v[x]; else f[x][j]=0;
    }
    int main()
    {
        n=read(); m=read();
        for (int i=1;i<=n;i++) w0[i]=read(); 
        for (int i=1;i<=n;i++) v0[i]=read();
        for (int i=1;i<=n;i++)
        {
            int x=read();
            if (x) insert0(x,i);
        }
        tarjan();
        memset(vis,0,sizeof(vis));
        rebuild();
        for (int i=1;i<=cnt;i++)
            if (!vis[i]) insert(cnt+1,i);
        dp(cnt+1);
        printf("%d",f[cnt+1][m]);
        return 0;
    }
  • 相关阅读:
    手机端上传图片及java后台接收和ajaxForm提交
    JEECG中datagrid方法自定义查询条件
    微信分享到朋友圈按钮 右上角提示
    Js获取后台集合List的值和下标的方法
    redis系列之数据库与缓存数据一致性解决方案
    替换{0}为指定的字符串(MessageFormat)
    java中对array数组的常用操作
    面试题-Java Web-网络通信
    你应该知道的JAVA面试题
    各大互联网公司java开发面试常问问题
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4708901.html
Copyright © 2020-2023  润新知