1. 程式人生 > >【DP】疊放箱子問題(兩種方法)

【DP】疊放箱子問題(兩種方法)

題目描述

某港口有一批集裝箱,將其編號,分別為1至N。每一個箱子的外型尺寸都是一樣的,現在要將其中某些集裝箱疊放起來,集裝箱疊放的規則如下:
  1)每個集裝箱上最多隻能直接疊放一個集裝箱。
  2)編號較小的集裝箱不能放在編號較大的集裝箱之上。
  3)每個集裝箱都給出了自身的重量和可承受的重量,每個集裝箱之上的所有集裝箱重量之和不得超過該集裝箱的可承受的重量。
  現在要求你程式設計,從中選出最多個集裝箱,使之在滿足以上條件的情況下疊放起來,即要求疊得儘可能地高。

輸入

第一行是一個正整數N,表示共有N個集裝箱(1≤ N ≤1000)。
  以下共有N行,每行兩個正整數,中間用空格分隔,分別表示每個集裝箱的自身重量和可承受的重量,兩個數均為小於等於3000。

輸出

輸出最多可疊放的集裝箱總數。

樣例

輸入

5  
19 15 
7 13 
5 7 
6 8 
1 2

輸出

4

方法1

時間複雜度O(6000n)

解題思路()

設F[i,j]表示第i個箱子到第N個箱子中總重量為j的最大箱子數,定w[i]表示第i個箱子的自身重量,定c[i]為第i個箱子的承受重量。
狀態轉移方程(不放和放):
在這裡插入圖片描述
其中,要 j > =

w [ i ] j>=w[i] && c [ i
] > = j w [ i ] c[i]>=j-w[i]
才可以放箱子上去

程式碼

#include<iostream>
#include<cstdio>
using namespace std;
int w[1001],c[1001],f[1005][6005],ans,n;
int main()
{
	 memset(f,-127/3,sizeof(f));//給f賦一個較小的值,便於後面的求判斷
	 scanf("%d",&n);
	 for (register int i=1;i<=n;++i)
	 	scanf("%d%d",&w[i],&c[i]);
	 f[n+1][0]=0;//設定最頂端箱子上一個沒重量,要不然會影響結果 
	 for (register int i=n;i>=1;--i)
	 {
	 	for (register int j=0;j<=6000;++j)
	 	{
	 		f[i][j]=f[i+1][j];//不放的情況
	 		if (j>=w[i]&&c[i]>=j-w[i])
	 		 f[i][j]=max(f[i][j],f[i+1][j-w[i]]+1);//放箱子的情況
	 	}
	 }
	 for (register int i=0;i<=6000;++i)
	  ans=max(ans,f[1][i]);//求出最大疊放數量
	 printf("%d",ans);  
}

適用於n比較大,但是每個的自身重量很小的情況。

方法2

時間複雜度 O(n^2)

解題思路

f [ i ] [ j ] f[i][j] 表示第i個箱到第N個箱子疊放j個箱子時可承受的最小重量。
狀態轉移方程:
f [ i ] [ j ] = m i n ( f [ i ] [ j ] f [ i + 1 ] [ j 1 ] + w [ i ] ) f[i][j]=min(f[i][j],f[i+1][j-1]+w[i])
因為總共就放j個箱子,所以多放一個箱子j就要少一個。
其中,要 j &gt; 0 j&gt;0 && c [ i ] &gt; = f [ i + 1 ] [ j 1 ] c[i]&gt;=f[i+1][j-1] 才可以放箱子上去
最後再找出最大的 j j 並輸出就可以了。

程式碼

#include<iostream>
#include<cstdio>
using namespace std;
int n,w[3001],c[3001],f[1005][6005];
int main()
{             
	int inf=1000000000;
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	 scanf("%d%d",&w[i],&c[i]);
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=n;j++)
	  f[i][j]=inf;//定初值
	f[n][0]=0;
	f[n][1]=w[n];//定初值
	for (int i=n-1;i>=1;i--)
	{
		for (int j=1;j<=n;j++)
		{
			f[i][j]=f[i+1][j];
			if ((j>0)&&(f[i+1][j-1]<=c[i]))
			 f[i][j]=min(f[i][j],f[i+1][j-1]+w[i]);
		}
	}
	int k;
	for (k=n;k>=1;k--)
	 if (f[1][k]!=inf) break;//找出最大的可疊放箱子數。
	printf("%d",k); 
}

適用於n比較小的,每個的自身重量很大的情況