zoukankan      html  css  js  c++  java
  • poj 2754 Similarity of necklaces 2 转换成多重背包,单调队列优化/ 二进制优化

      贴个官方解题报告

    Similarity of necklaces 2
    
    这个问题是一个012背包问题。我们知道01背包只要逆向线性检索,无限背包只要正向检索。012背包就是说,每个物品有一个数量上限。这个问题可以用log方法,也存在线性方法,需要维护一个递增/递减序列。
    
    我们先把所有的Table都放成下限,接下来我们可以算出它距离总和为0还需要增加多少。对于1<=i<=M,它可以看成这样一个物品:体积为Multi[i],费用为Pairs[i],数量为Up[i]-Low[i]。然后就得到一个012背包问题了。
    
    复杂度约为:O(M*背包大小)。其中背包大小不超过M*20*25=200*20*25=100000

      单调队列优化解法:

        多重背包状态方程:

            

        令  转换下得到:

            

        因为 , 当 j 确定时, 则x的取值范围为,  

        也就是说    ,  也可看作为 

        则可得

                ,其中 j <= k

        那么意味着,对于确定的 j, 求 Xk 时候,我们只需要对  维护一个单调队列即可。

        对于任意的 Xi < Xj, 若 Xb 优于 Xa,则必将满足如下要求, 

        

        这种写法 AC时间是 1500ms,有点慢    

    View Code
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 210;
    const int N = 100000+10;
    const int inf = -2139062144;
    int dp[2][N];
    int P[maxn], M[maxn], Low[maxn], Up[maxn];
    int n, m, Q[N], cnt[maxn], val;
    int max(int a,int b) {return a>b?a:b;}
    int main()
    { 
        while( scanf("%d", &n) != EOF)
        {
            m = 0; val = 0;    
            for(int i = 1; i <= n; i++)
            {    
                scanf("%d%d%d%d",P+i,M+i,Low+i,Up+i);
                m += Low[i]*M[i];
                val += Low[i]*P[i];    
                cnt[i] = Up[i]-Low[i];    
            }    
            memset(dp, 0x80, sizeof(dp));
            dp[0][0] = 0;    
        
            m = -m;
            int cur = 0;
            for(int i = 1; i <= n; i++)
            {
                int nxt = cur^1;
                // 枚举剩余系j    
                for(int j = 0; j < M[i]; j++)
                {
                    //单调队列队首指针qh,队尾指针qe, 当前最大长度len    
                    int qh = 0, qe = -1, len = cnt[i]*M[i];
                    for(int k = j; k <= m; k += M[i] )
                    {
                        if( dp[cur][k] != -inf )
                        {
                            while( (qh <= qe) && (dp[cur][ Q[qe] ]+(k-Q[qe])*P[i]/M[i] <= dp[cur][k] ) )
                                qe--;
                            Q[++qe] = k;    
                            while( (qh <= qe) && (k-Q[qh]>len) ) qh++;
                            if(qh <= qe)    dp[nxt][k] = dp[cur][ Q[qh] ] + (k-Q[qh])*P[i]/M[i];
                            else    dp[nxt][k] = -inf;    
                        }
                    }
                }
                cur = nxt;    
            }
            printf("%d\n", dp[cur][m]+val );    
        }
        return 0;
    }

        

        将其转换成 01背包:

          套用 背包九讲 的二进制写法就可以了,一样将Table取下限,转换出一个物品数量。

          模板是处理第i种物品时, 若其 体积*数量 >= 总背包大小, 则当作完全背包处理,

          否则 将其按照 二进制表示的形式,当作一次 01背包来处理。代码400MS左右,比上面写法快

    View Code
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    using namespace std;
    
    const int inf = 0x80808080;
    const int N = 100010;
    int n, V, val;
    int P[210], M[210], cnt[210];
    int dp[N];
    
    int max(int a,int b)
    { return a>b?a:b; }
    
    void ZeroOnePack( int cost, int weight )
    {
        for(int v = V; v >= cost; v-- )    
            dp[v] = max( dp[v], dp[v-cost] + weight );
    }
    void CompletePack( int cost, int weight )
    {
        for(int v = cost; v <= V; v++ )
            dp[v] = max( dp[v], dp[v-cost] + weight );
    }
    void MultiplePack( int cost, int weight, int num )
    {
        if( cost*num >= V )
        {    
            CompletePack( cost, weight );
            return ;
        }
        int k = 1;
        while( k <= num )
        {
            ZeroOnePack( k*cost, k*weight );
            num = num-k;
            k <<= 1;
        }
        ZeroOnePack( num*cost, num*weight );
    }
    int main()
    {
        while( scanf("%d",&n) != EOF)
        {
            V = 0; val = 0;
            int up, low;
            for(int i = 1; i <= n; i++)
            {
                scanf("%d%d%d%d",P+i,M+i,&low,&up);
                V += low*M[i];
                val += low*P[i];
                cnt[i] = up-low;    
            }
            V = -V;
            memset( dp, 0x80, sizeof(dp));
            dp[0] = 0;
            for(int i = 1; i <= n; i++)
                MultiplePack( M[i], P[i], cnt[i] );    
            
            printf("%d\n", dp[V]+val );
        }    
        return 0;
    }

        

        

  • 相关阅读:
    Composite in Javascript
    Model Validation in Asp.net MVC
    HttpRuntime.Cache vs. HttpContext.Current.Cache
    Controller Extensibility in ASP.NET MVC
    The Decorator Pattern in Javascript
    The Flyweight Pattern in Javascript
    Model Binding in ASP.NET MVC
    Asp.net MVC
    jQuery Ajax 实例 全解析
    ASP.NET AJAX入门系列
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2866808.html
Copyright © 2011-2022 走看看