旅遊揹包(多維有界的揹包問題)

描述:

想去旅遊嗎?那得先準備揹包!

揹包用來裝旅遊物品,現在共n種(n<=50)旅遊物品,每種物品都有體積vi,重量wi,數量ci,價值ti (vi,wi,ci和ti都爲整數)。
限制體積最多V立方厘米(V<=1000),重量最多W公斤(W<=500)。

請問你如何選擇物品,使得帶上的物品總價值最大,這個最大總價值爲多少?

比如:
物品     體積       重量    數量    價值
編號  (立方厘米)  (公斤)   (個)    (元)
  1        30          3        10       4
  2        50          8        10       5
  3        10          2        10       2
  4        23          5        8        3
  5        130         20       5        11

若V爲500,W爲100,則選擇物品的最大價值爲72(且72=10*4+10*2+4*3:由10件物品1,10件物品3,和4件物品4組成)。

這是一個多維且有界的揹包問題,屬於常規0-1揹包問題的擴展問題。

輸入格式:
第一行,物品的種類n,揹包體積的限制V,揹包載重量的限制W。n,V和W的範圍如前所述。
接下來n行,每行爲該種物品i的體積vi,重量wi,數量ci,價值ti (規定vi,wi,ci和ti都爲整數)。

輸出格式:
僅一行,爲選擇物品子集所能獲得的最大價值。
輸入樣例:
5 500 100
30 3 10 4
50 8 10 5
10 2 10 2
23 5 8 3
130 20 5 11

輸出樣例:
72

分析:
 發現對於這個題目,很多同學使用直接的遞歸方式完成,這裏使用動態規劃的方法完成。

 n種物品,每種物品體積v[i],重量w[i],c[i]件,價值t[i]。
設:m[i][x][y] 表示可選前i 種物品,所選物品總體積不超過x ,總重量不超過y ,的最大價值。
首先對三維數組初始化爲0;

存在如下遞歸關係:
當 i=1 時:
m[1][x][y]=0                                      x<v[1]||y<w[1];
m[1][x][y]=min(x/v[1],y/[w[1],c[1])*t[1]          x>=v[1]&&y>=w[1];

當 i>1 時:
m[i][x][y]=max{m[i-1][x][y],m[i-1][x-k*v[i]][y-k*w[i]]+k*t[i]}      x>=v[i]&&y>=w[i];   其中:  0<k<min(x/v[i],y/w[i],c[i]);
m[i][x][y]=m[i-1][x][y]                                             x<v[i]||y<w[i];                     
k表示揹包能放入i物品最多的件數;
	
代碼如下:

#include<iostream>
using namespace std;


int m[51][1001][501]={0};     //m[i][j][k] 表示可選前i 種物品,總體積不超過j, 總重量不超過k 的最大值
int v_arr[51];                //物品體積
int w_arr[51];                //重量
int c_arr[51];               //件數
int t_arr[51];               //價值



int min(int a,int b,int c){        //三個數找最小
	int m;
	m=a;
	if(b<m)
		m=b;
	if(c<m)
		m=c;
	return m;
}


void func(int v,int w,int n){    //可選前n個物品,體積不超過v,重量不超過w
      
     int i=0,j=0;
     int x=0,y=0;
	 int k=0,max=0;


    for(x=0;x<=v;x++)
		for(y=0;y<=w;y++)
			if((x/v_arr[1]>0)&&(y/w_arr[1]>0))                               //x>=v_arr[1]&&y>=w_arr[1]
				m[1][x][y]=min(x/v_arr[1],y/w_arr[1],c_arr[1])*t_arr[1];     //m[1][x][y]取最大值
			else
				m[1][x][y]=0;                                                //x<v_arr[1]&&y<w_arr[1]                   


	for(i=2;i<=n;i++)                                             //從第i=2開始填充
		for(x=0;x<=v;x++)
			for(y=0;y<=w;y++){
				max=m[i-1][x][y];
				if((x>=v_arr[i])&&(y>=w_arr[i])){
				   for(k=0;k<=min(x/v_arr[i],y/w_arr[i],c_arr[i]);k++)
                     if((m[i-1][x-k*v_arr[i]][y-k*w_arr[i]]+k*t_arr[i])>max)         //找出符合的最大的
						 max=(m[i-1][x-k*v_arr[i]][y-k*w_arr[i]]+k*t_arr[i]);
					 m[i][x][y]=max;
				}
                else
					m[i][x][y]=m[i-1][x][y];
			}

     }


int main(){
   int n=0;    //物品種類
   int v=0;    //揹包體積
   int w=0;    //揹包載重
 

   cin>>n>>v>>w;
   
   for(int i=1;i<=n;i++)
       cin>>v_arr[i]>>w_arr[i]>>c_arr[i]>>t_arr[i];
       
   func(v, w, n);
   cout<<m[n][v][w];
   return 0;
}


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