疊放箱子問題(方法一)【DP】
阿新 • • 發佈:2018-12-16
> Description
有一堆十分之麻煩的箱子需要你幫忙豎著疊放:
1.編號小的箱子必須放在編號大的之下;
2.每個箱子上面只能放一個箱子;
3.每個箱子都有它的自身重量和承受重量,必須保證這個箱子之上所有箱子的重量不超過這個箱子的承受重量。
更麻煩的是,還要你算出n個箱子按照這樣的方式來疊放,最多可以疊放多少個箱子。
> Input
第一行輸入箱子數n(1≤ N ≤1000)。
接下來n行分別輸入第i個箱子的自身重量和承受重量,兩個數均為小於等於3000。
> Output
輸出最多的箱子數
> Sample Input
5
19 15
7 13
5 7
6 8
1 2
> Sample Output
4
> 解題思路
按照老師的話來說這一道題十分考驗智商。。。 這一道題用DP來解。
因為這個箱子很讓人禿頭,又要按順序又要保證不超過承受重量的,所以這個方法是從上往下看的,就是f[i][j]表示的是從i到n這些箱子中總重量為j的最優值,它按照這個思維排箱子也不是從下往上壘的,而是從上往下的(我理解為它是在半空中排箱子)。
然後算的時候就有些像揹包了 說明揹包真的很重要 ,
狀態轉移方程(要麼選要麼不選):
f[i][j]=max(f[i+1][j],f[i+1][j-w[i]]+1)
i+1因為是從上往下的,所以之前一個階段應該是在i+1這裡;j-w[i]是因為j是總重量,要選擇第i個箱子拍下去就應該空出位置給它。
判斷:j>=w[i]防止算出負數,越界
c[i]>=j-w[i]按照題目描述那樣,必須上面的總重量必須小於等於承受重量,j為總重量,再減去這個箱子的重量就等於上面箱子的重量。
> 程式碼
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,c[1005],w[1005],f[1005][6005]={0};
int main()
{
int ans=0;
scanf("%d",&n);
for(int i= 1;i<=n;i++) scanf("%d%d",&w[i],&c[i]);
for(int i=n;i>=1;i--)
for(int j=1;j<=6000;j++)
//6000是因為箱子自身重量和承受重量分別最多為3000,而j為它們的總重量
{
if(j>=w[i]&&c[i]>=j-w[i]) //判斷
f[i][j]=max(f[i+1][j],f[i+1][j-w[i]]+1);
//+1——增加一個箱子
else f[i][j]=f[i+1][j]; //不然就不選
}
for(int i=1;i<=6000;i++)
ans=max(ans,f[1][i]);
//最多箱子數的總重量是不定的,所以要迴圈判斷一下
printf("%d",ans);
return 0;
}