(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; }
(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; }