1. 程式人生 > >Bookshelf 2(poj3628,01揹包,dp遞推) 對01揹包的分析與理解(圖文)

Bookshelf 2(poj3628,01揹包,dp遞推) 對01揹包的分析與理解(圖文)

題目連結:Bookshelf 2(點選進入)

題目解讀:

給n頭牛,給出每個牛的高度h[i],給出一個書架的高度b(所有牛的高度相加>書架高度b),現在把一些牛疊起來(每頭牛隻能用一次,但不同的牛可能身高相同),在這些疊起來的牛的總高度>書架b的基礎上,找出最小的差距(由於輸入的資料會保證所有牛的高度相加>書架高度b,所以差距不為負)

還是看不懂題目?

舉個栗子:

現在有五頭牛高度分別為3 1 3 5 6,書架高度b=16,我們可以把五頭牛都疊起來,總高度為18,差距為18-16=2,但這樣差距不是最小的,最小的差距是:(3+3+5+6)-16=1

 

這題可以看成01揹包是每個牛隻能選一次或者不選,然後我們可以先忽略書架高度b,對於單個牛高度h[i],我們可以看成 價值[i]=佔用空間[i]=h[i]

,因為牛的佔用空間就是高度也就是他的價值,畢竟最後需要總高度>b,那這不就是總價值>b

我在寫的時候卡在如何處理最小差距,原來最後是這樣的:如果我們按平常01去運算,最後會得到一個f[]數組裡面塞滿了資料,並且從左到右是不降低的,f[j]的意義就是容量為j時的最大總高度,那麼j是從1~sum(所有牛高度和)的,比如說書架高度為b=15,當f[j]的值<b,那麼如果f[j+1]的值>=b了,則f[j+1]-b就是我們要的高度,因為f[j]到f[j+1]的空間最大容量只加了1,而牛的高度最起碼>=1吧

這題在普通的01揹包基礎上,還在最後加入了選擇資料的過程

因為陣列f[]從左到右是恆不降低的,那麼直接從左到右找出第一個>=b的f[j]就是最小差距了

下面的程式碼涉及滾動陣列與01揹包空間優化,如果不瞭解建議先看我的另一篇:對01揹包的分析與理解(圖文)

下面上程式碼

#include<cstdio>
#include<iostream>
#include<string.h>
#define ll long long
using namespace std;
ll h[25];//存放每個牛的高度
int main()
{
    ll n,b,sum=0;
    cin>>n>>b;
    for(ll i=1;i<=n;i++)
    {
        scanf(
"%lld",&h[i]); sum+=h[i];//sum為所有奶牛高度和 } ll f[sum+10]; memset(f,0,sizeof(f));//清空陣列 for(ll i=1;i<=n;i++) for(ll j=sum;j>=h[i];j--) { f[j]=max(f[j],f[j-h[i]]+h[i]);//看作價值=佔用空間=高度 } for(ll i=1;i<=sum;i++) if(f[i]>=b)//如果差距>=0 { cout<<f[i]-b<<endl; return 0; } }
點選加號檢視程式碼