POJ2754 Similarity of necklaces 2 (多重背包+二进制优化)

这道题目简直是一道阅读理解题,我看了半天没看懂问什么,后来靠翻译看懂了,我来把他翻译一下

现在有M个物品,每个物品费用为p[i],体积为w[i],可以有low[i]-up[i]个物品可以取,假设你取table[i]个物品,问你当满足所有w[i]*t[i]的和为0的情况下,怎么取能使p[i]*table[i]最大

这题乍一看很难的,因为满足那个条件我们不知道如何去限制他,但是经过仔细观察(题解),我们可以发现,我们不妨转化一下思路,这也是最关键的一点,看出这个这题就做出来了

我们先将sum=所有w[i]*low[i]的值,也就是先提前取掉low[i]个,那么剩下能取0--up[i]-low[i]个,那么只要table[i]*w[i]的和等于-sum就能满足题目条件了

这就发现了是多重背包问题,当体积一定时,求取最大的费用,每个物品能选指定次数

但是这还不够,如果暴力枚举多维,会超时,所以我们用到了二进制优化,大大减小了复杂度,我想如果您能做到这题,应该已经会二进制优化了,如果不会的话,可以去ACWing网站学习

下面看代码注释:

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int N=1e5+10;
int w[N],l[N],u[N],p[N];
int sum;
int tmp;
int f[N]; 
int cnt;
int a[N];
int b[N];
int main(){
    int i;
    int n;
    while(cin>>n){

    tmp=0;
    cnt=0;
    sum=0;
    for(i=1;i<=n;i++){
        scanf("%d%d%d%d",&p[i],&w[i],&l[i],&u[i]);
        tmp+=p[i]*l[i];  //先算出初始费用 
        sum+=w[i]*l[i]; //所需的总体积 
        u[i]-=l[i];
    }
    sum=-sum;  //取相反数,因为相加为0,所以是-sum 
    memset(f,-0x3f,sizeof f);
    f[0]=0;
    for(i=1;i<=n;i++){
        int k=1;
        while(k<=u[i]){
            cnt++;
            a[cnt]=k*p[i]; //二进制优化,所有的情况都能用这样的方式枚举出来 
            b[cnt]=k*w[i];
            k<<1;
            u[i]-=k;
        }
        if(u[i]){
            cnt++;
            a[cnt]=u[i]*p[i];
            b[cnt]=u[i]*w[i];
        }
    }
    n=cnt;
    int j;
    for(i=1;i<=n;i++){
        for(j=sum;j>=b[i];j--){  //滚动数组优化,所以倒着枚举 
            f[j]=max(f[j],f[j-b[i]]+a[i]);
        }
    }
    cout<<f[sum]+tmp<<endl;}
    
} 
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12295215.html