• 2016 USP Try-outs L. The Knapsack problem(超大容量完全背包)


    https://codeforces.com/gym/101064/problem/L

    背包容量S特别大,但是每个物品重量相比之下比较小

    令mx表示所有物品中重量最大的,把S拆分成两部分,S=A+B 且 |A-B|<=mx

    因为如果A和B的重量相差超过mx,可以把mx从重的那一部分放到轻的那一部分

    即|A-(S-A)|<=mx

    所以 S/2-mx/2 <= A <= S/2+mx/2

    同理为了求出 f(S/2-mx/2)到 f(S/2+mx/2)

    就要求出 f(S/4- mx*3/4)到 f(S/4+mx*3/4)

    这样一直往下

    整个mx的偏移范围不会超过[-mx,mx]

    所以所有需要求的就是 f(S/2^k-mx)到  f(S/2^k+mx)

    状态数为log(S)*mx*2个

    每个状态枚举mx的偏移范围平方求即可

    复杂度为log(S)*mx^2

    #include<bits/stdc++.h>
    
    using namespace std;
    
    typedef long long LL;
    
    LL dp[101][4001],f[4001]; 
    int low[101];
    int w[1001],c[1001];
    
    int main()
    {
        int T,n,m,mx,cnt;
        
            scanf("%d%d",&n,&m);
            mx=0;
            for(int i=1;i<=n;++i) 
            { 
                scanf("%d%d",&w[i],&c[i]);
                mx=max(mx,w[i]);
            }
            cnt=0;
            while(m)
            {
                low[++cnt]=m-mx;
                m/=2;
            }
            memset(f,0,sizeof(f));
            for(int i=1;i<=n;++i)
                for(int j=w[i];j<=2*mx;++j)
                    f[j]=max(f[j],f[j-w[i]]+c[i]);
            for(int i=cnt;i;--i)
                for(int j=low[i];j<=low[i]+mx*2;++j)
                    if(j<=2*mx) dp[i][j-low[i]]=f[j];
                    else
                        for(int k=(j-mx)/2;k<=j/2;++k)
                            dp[i][j-low[i]]=max(dp[i][j-low[i]],dp[i+1][j-k-low[i+1]]+dp[i+1][k-low[i+1]]);
            printf("%lld",dp[1][mx]);
        
    }
    作者:xxy
    本文版权归作者和博客园共有,转载请用链接,请勿原文转载,Thanks♪(・ω・)ノ。
  • 相关阅读:
    Supreme(ง •̀_•́)ง
    基于VS快速排序的单元测试
    POST GET
    Go对比其他语言新特性1(字符类型、类型转换、运算符、键盘输入、for、switch)
    四则运算问题
    软件工程第三次作业!
    Servlet
    结对编程1
    Kafka技术原理知识点总结
    KafkaStream简介
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/15122445.html
Copyright © 2020-2023  润新知