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

    传送门

    一开始我以为这道题是一个比较正常的分组背包,只不过原来做的题目的限制条件是数目,这次是有体积(软件所占空间)的限制,但是两者好像没什么差异……

    于是我就仿着正常的分组背包写了一下,然后过了样例。我才不会告诉你我一开始结果全是0,因为我写错了

    交上去一看只有10分……

    回来发现原来这题并没有说是一棵树……orz,那我们来看一看每一个环,每个环里面所有的软件要么全选,要么全不选,所以直接看成一个强连通分量缩点,把体积和价值都合起来即可。就像炉石那张融合所以我们缩点,之后把所有入度为0的点向虚拟节点连边,之后开始正常DP。但是我一开始发现建出来的图是反的,这样就行不成树了。不过想起了tarjan求强连通分量的时候,因为我把树建成了有向图,所以肯定原来的起点现在还应该是起点,就把建图反了过来,之后就神奇的AC啦!

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 1005;
    const int INF = 1000000009;
    const ll mod = 1e9+7;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct node
    {
        int next,to,from;
    }e[M<<1];
    
    int m,n,dp[M][M],v[M],x,y,head[M],ecnt,size[M],w[M],dfn[M],scc[M],idx,low[M],stack[M],top,cnt;
    int rdeg[M],tot;
    bool vis[M];
    
    void add(int x,int y)
    {
        e[++ecnt].to = y;
        e[ecnt].next = head[x];
        e[ecnt].from = x;
        head[x] = ecnt;
    }
    
    void tarjan(int x)
    {
        low[x] = dfn[x] = ++idx;
        stack[++top] = x,vis[x] = 1;
        for(int i = head[x];i;i = e[i].next)
        {
        if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]);
        else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]);
        }
        if(low[x] == dfn[x])
        {
        int p;
        cnt++;
        while((p = stack[top--]))
        {
            scc[p] = cnt,vis[p] = 0,v[cnt] += v[p],w[cnt] += w[p];
            if(p == x) break;
        }
        }
    }
    
    void rebuild()
    {
        rep(i,1,ecnt)
        {
        int r1 = scc[e[i].from],r2 = scc[e[i].to];
        if(r1 != r2) add(r2,r1),rdeg[r1]++;
        }
        rep(i,n+1,cnt)
        {
        dp[i][0] = v[i];
        if(!rdeg[i]) add(0,i);
        }
    }
    
    void dfs(int x,int fa)
    {
        for(int i = head[x];i;i = e[i].next)
        {
        int t = e[i].to;
        if(t == fa) continue;
        dfs(t,x);
        per(j,m,1)
        {
            rep(p,0,j-w[t]) dp[x][j] = max(dp[x][j],dp[x][j-p-w[t]] + dp[t][p]);
        }
        //rep(j,0,m) printf("%d ",dp[x][j]);enter;
        //printf("#%d %d
    ",x,dp[x][0]);
        }
    }
    
    int main()
    {
        n = read(),m = read();
        rep(i,1,n) w[i] = read();
        rep(i,1,n) v[i] = read();
        rep(i,1,n)
        {
        x = read();
        if(x != 0) add(i,x);
        }
        cnt = n,tot = ecnt;
        rep(i,1,n) if(!dfn[i]) tarjan(i);
        rebuild();
        //rep(i,tot+1,ecnt) printf("%d %d
    ",e[i].from,e[i].to);
        dfs(0,0);
        printf("%d
    ",dp[0][m]);
        return 0;
    }
  • 相关阅读:
    tyvj 1031 热浪 最短路
    【bzoj2005】 [Noi2010]能量采集 数学结论(gcd)
    hdu 1394 Minimum Inversion Number 逆序数/树状数组
    HDU 1698 just a hook 线段树,区间定值,求和
    ZeptoLab Code Rush 2015 C. Om Nom and Candies 暴力
    ZeptoLab Code Rush 2015 B. Om Nom and Dark Park DFS
    ZeptoLab Code Rush 2015 A. King of Thieves 暴力
    hdoj 5199 Gunner map
    hdoj 5198 Strange Class 水题
    vijos 1659 河蟹王国 线段树区间加、区间查询最大值
  • 原文地址:https://www.cnblogs.com/captain1/p/9814356.html
Copyright © 2011-2022 走看看