多重背包及其優化


(1)二進制的優化

這是一個多重背包的模板,也是十分好用的一種模板,因為這個比直接拆除01 背包來做

要省些時間。這是為啥呢,首先先由我講一下為什么能換成01 背包吧。

舉個例子。假如給了我們 價值為 2,但是數量卻是10 的物品,我們應該把10給拆開,要知道二進制可是能夠表示任何數的,所以10 就是可以有1,2, 4,8之內的數把它組成,一開始我們選上 1了,然后讓10-1=9,再選上2,9-2=7,在選上 4,7-4=3,

而這時的3<8了,所以我們就是可以得出 10由 1,2,4,3,來組成,就是這個數量為1,2,3,4的物品了,那么他們的價值是什么呢,是2,4,6,8,也就說給我們的價值為2,數量是10的這批貨物,已經轉化成了價值分別是2,4,6,8元的貨物了,每種只有一件哎!!!!這就是二進制優化的思想。

 

那為什么會有完全背包和01 背包的不同使用加判斷呢?原因也很簡單啊,當數據很大,大於背包的容納量時,我們就是在這個物品中取上幾件就是了,取得量時不知道的,也就理解為無限的啦,這就是完全背包啦,反而小於容納量的就是轉化為01背包來處理就是了,可以大量的省時間。

AC代碼:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 1000         //物品個數 
#define M 100000000    //所有物品可能的最大價值 
int m[N],c[N],w[N],f[M];
int V;
int max(int a,int b){return a>b?a:b;}
void ZeroOnePack(int cost,int weight)
{
    int v;
    for(v=V;v>=cost;v--) f[v]=max(f[v],f[v-cost]+weight);
}
void CompletePack(int cost,int weight)
{
    int v;
    for(v=cost;v<=V;v++)
        f[v]=max(f[v],f[v-cost]+weight);
}
void MultiplePack(int cost,int weight,int amount)
{
    int k;
    if(cost*amount>=V)
    {
        CompletePack(cost,weight);
        return;
    }
    k=1;
    while(k<amount)
    {
        ZeroOnePack(k*cost,k*weight);
        amount=amount-k;
        k=k*2;
    }
    ZeroOnePack(amount*cost,amount*weight);
}
int main()
{
    int n,i;
    scanf("%d %d",&n,&V);
                                                   // 兩種不同的初始化方式,根據情況自行選擇 
    //memset(f,0,sizeof(f[0])*(V+1));              // 只希望價格盡量大 
    //memset(f,-M,sizeof(f[0])*(V+1));f[0]=0;      // 要求恰好裝滿背包 
    for(i=0;i<n;i++) scanf("%d %d %d",m+i,c+i,w+i);
    for(i=0;i<n;i++) MultiplePack(c[i],w[i],m[i]);
    printf("%d\n",f[V]);
    system("PAUSE");
    return 0;
}
View Code

(2)單調隊列優化

解析

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#define ll long long
using namespace std;
int n,m,he,ta,T;
ll f[10010],q[10010],num[10010];
int main()
{
    int i,j,w,v,s,d;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(i=0;i<=m;i++)f[i]=0;
        for(i=1;i<=n;i++){
            scanf("%d%d%d",&w,&v,&s);
            if(s>m/w)s=m/w;
            for(d=0;d<w;d++){
                he=ta=1;
                for(j=0;j<=(m-d)/w;j++){//先存進去,后取出來
                    int tmp=f[j*w+d]-v*j;
                    while(he<ta&&q[ta-1]<=tmp)--ta;
                    q[ta]=tmp,num[ta++]=j;
                    while(he<ta&&j-num[he]>s)++he;
                    f[j*w+d]=max(f[j*w+d],q[he]+v*j);
                }
            }
        }
        printf("%lld\n",f[m]);
    }
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM