zoukankan      html  css  js  c++  java
  • 软件安装「HAOI2010」

    题意

    (n)个软件,每个软件都可能有一个依赖软件(换言之,不安装依赖软件就不能安装该软件)。每个软件都有自己的容量和价值,已知总容量,求最大价值。


    思路

    tarjan+树上背包裸题。

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    namespace StandardIO {
    
        template<typename T>inline void read (T &x) {
            x=0;T f=1;char c=getchar();
            for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
            for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
            x*=f;
        }
    
        template<typename T>inline void write (T x) {
            if (x<0) putchar('-'),x*=-1;
            if (x>=10) write(x/10);
            putchar(x%10+'0');
        }
    
    }
    
    using namespace StandardIO;
    
    namespace Project {
    
        const int N=505;
    
        int n,m,tim,top,num;
        int cnt,cnt2;
        int head[N],head2[N];
        struct node {
            int to,next;
        } edge[N<<1],edge2[N<<1];
        int dfn[N],low[N],sta[N],instack[N],belong[N];
        int cost[N],W[N],V[N],G[N][N],d[N],f[N][N],val[N];
    
        inline void add (int a,int b) {
            edge[++cnt].to=b,edge[cnt].next=head[a],head[a]=cnt;
        }
        inline void add2 (int a,int b) {
            edge2[++cnt2].to=b,edge2[cnt2].next=head2[a],head2[a]=cnt2;
        }
        void tarjan (int now) {
            dfn[now]=low[now]=++tim;
            sta[++top]=now,instack[now]=1;
            for (register int i=head[now]; i; i=edge[i].next) {
                int to=edge[i].to;
                if (!dfn[to]) {
                    tarjan(to),low[now]=min(low[now],low[to]);
                } else if (instack[to]) low[now]=min(low[now],dfn[to]);
            }
            if (dfn[now]==low[now]) {
                int v;belong[now]=++num,instack[now]=0;
                while (v=sta[top--],v!=now) {
                    belong[v]=num,instack[v]=0;
                }
            }
        }
        void dp (int now) {
            for (register int i=cost[now]; i<=m; ++i) f[now][i]=val[now];
            for (register int e=head2[now]; e; e=edge2[e].next) {
                int to=edge2[e].to;
                dp(to);
                for (register int i=m-cost[now]; i>=0; --i) {
                    for (register int j=0; j<=i; ++j) {
                        f[now][i+cost[now]]=max(f[now][i+cost[now]],f[now][i+cost[now]-j]+f[to][j]);
                    }
                }
            }
        }
    
        inline void MAIN () {
            read(n),read(m);
            for (register int i=1; i<=n; ++i) read(W[i]);
            for (register int i=1; i<=n; ++i) read(V[i]);
            for (register int i=1; i<=n; ++i) {
                int x;read(x);
                if (x) add(x,i);
            }
            for (register int i=1; i<=n; ++i) if (!dfn[i]) tarjan(i);
            for (register int i=1; i<=n; ++i) {
                cost[belong[i]]+=W[i],val[belong[i]]+=V[i];
                for (register int e=head[i]; e; e=edge[e].next) {
                    int to=edge[e].to;
                    if (belong[i]!=belong[to]) G[belong[i]][belong[to]]=1,d[belong[to]]++;
                }
            }
            for (register int i=1; i<=num; ++i) {
                for (register int j=1; j<=num; ++j) {
                    if (G[i][j]) add2(i,j);
                }
            }
            for (register int i=1; i<=num; ++i) {
                if (!d[i]) add2(num+1,i);
            }
            dp(num+1);
            printf("%d
    ",f[num+1][m]);
        }
    
    }
    
    int main () {
    //    freopen(".in","r",stdin);
    //    freopen(".out","w",stdout);
        Project::MAIN();
    }
    
  • 相关阅读:
    Linux/Unix中的#!和!#
    包含min函数的栈
    顺时针打印矩阵
    二叉树镜像
    数的子结构
    合并两个排序的链表
    反转链表
    链表中倒数第K个结点
    调整数组顺序使奇数位于偶数前面
    在O(1)时间删除链表结点
  • 原文地址:https://www.cnblogs.com/ilverene/p/11402225.html
Copyright © 2011-2022 走看看