借用杭電飯卡問題來淺析 01揹包問題空間複雜度的優化

題目鏈接點擊打開鏈接

Problem Description

電子科大本部食堂的飯卡有一種很詭異的設計,即在購買之前判斷餘額。如果購買一個商品之前,卡上的剩餘金額大於或等於5元,就一定可以購買成功(即使購買後卡上餘額爲負),否則無法購買(即使金額足夠)。所以大家都希望儘量使卡上的餘額最少。
某天,食堂中有n種菜出售,每種菜可購買一次。已知每種菜的價格以及卡上的餘額,問最少可使卡上的餘額爲多少。

Input
多組數據。對於每組數據:
第一行爲正整數n,表示菜的數量。n<=1000。
第二行包括n個正整數,表示每種菜的價格。價格不超過50。
第三行包括一個正整數m,表示卡上的餘額。m<=1000。
n=0表示數據結束。

Output
對於每組輸入,輸出一行,包含一個整數,表示卡上可能的最小余額。
Sample Input
1 50 5 10 1 2 3 2 1 1 2 3 2 1 50 0
Sample Output
-45 32
這是一道典型的01揹包問題,只不過在上面又附加了一個限制條件(如果購買一個商品之前,卡上的剩餘金額大於或等於5元,就一定可以購買成功(即使購買後卡上餘額爲負),否則無法購買(即使金額足夠)),但最終問的問題還是迴歸到了01揹包問題(問最少可使卡上的餘額爲多少),那怎麼考慮這個問題呢?
我先給一組數據  按自己原始的想法去做  就會有大致的思路:
菜的數量:5    菜的價格分別爲: 4,7,18,7,12   飯卡上的餘額: 20
好了,現在要讓你買菜使得飯卡上的餘額最少。我說一下我的思路,根據限制條件我先扣除來最少5(雖然到時候剩餘的不一定是5快,但肯定要比5快多)塊錢,讓他去買最貴的那道菜(18塊錢的那道),然後剩餘的餘額和剩餘的菜進行01揹包,最後是這樣買的:扣除5快後,卡上餘額15,怎麼買呢?7+7=14這就是最好的選擇了(還剩餘1塊),最後5+1=6,去買最貴的那道菜6-18=-12。最終答案就是-12.
和原始01揹包問題的區別:
(1)這裏飯卡01揹包問題和物品裝到揹包裏面有個小小的區別就是物品裝揹包告訴了物品的價值和質量,而這裏沒告訴你質量,仔細一想就會發現,揹包把物品裝進去走之後就會把物品的質量減掉,這裏一樣的效果,買完菜就把菜價扣除掉,相對於物品放揹包,你可以把菜價看成,即是菜的價值也是菜的質量,再把餘額看成揹包容量
(2)還有就是,這裏不需要知道你到底買了那幾道菜,所以不用去尋找x[i]的值了
接着上篇博文,先看一下我一開始的代碼
#include "iostream"
#include "math.h"
#include "algorithm"
using namespace std;

int main()
{
	int a[1005],m[100][100],x[1005],n,sum,i,j,c;
	memset(a,0,sizeof(a));
	while(scanf("%d",&n)!=EOF&&n!=0)
	{
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	
	sort(a+1,a+n+1);
	cin>>c;
	memset(m,0,sizeof(m));
	if(c < 5)
	{
        printf("%d\n",c);
	}
	else
	{
        for(i = 1; i <= n-1; i++)  
	{
               for( j = 0; j <=c-5; j++)  
		{
                   m[i][j] = m[i-1][j];
		   if(j>=a[i])
		   {
                    m[i][j] = m[i-1][j] > m[i-1][j-a[i]] + a[i]? m[i-1][j] : m[i-1][j-a[i]] + a[i]; 
		   }
		}
	}
	    sum=c-m[n-1][c-5]-a[n];
	    cout<<sum<<endl;
	}
	}
}
注意這裏一開始我的m二維數組是這樣的m[1005][1005]結果運行之後是這樣
後來才知道是二維數組的問題,



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章