1. 程式人生 > >揹包問題,動態規劃求解,matlab程式碼,c++程式碼

揹包問題,動態規劃求解,matlab程式碼,c++程式碼

最近寫論文接觸到揹包問題,查閱網上一些資料,對於簡單的揹包問題,動態規劃演算法可以求解,最近花時間整理整理。

揹包問題描述:

有編號分別為a,b,c,d,e 的五件物品,它們的重量分別是 2,2,6,5,4,它們的價值分別是 6,3,5,4,6,現在給你個承重為 10 的揹包,如何讓揹包裡裝入的物品具有最大的價值總和 (假設每類物品可以裝多個)

根據求解動態規劃問題的步驟,一步一步來。用 ci 表示各物品的重量,vi 表示各物品的價值。

階段:

\begin{equation}i=1,2,\dots,5\end{equation}

第 i  階段表示檢查第 i 個物品。

狀態變數:

\begin{equation}S_{i}\qquad i=1,2,\dots,5\end{equation}

表示檢查第 i 個物品時包中的剩餘承重量。一個問題能夠用動態規劃演算法求解,必須保證狀態空間是有限的。

決策變數:

\begin{equation}x_{i}\qquad i=1,2,\dots,5\end{equation}

表示第 i 個物品裝入幾個。

狀態轉移方程:

\begin{equation}S_{i+1}=S_{i}-c_{i}x_{i}\end{equation}


最優收益函式:

\begin{equation}\mathop{f}(S_{i})\end{equation}

表示檢查第 i 個物品時,當包中剩餘承重為 Si,包中裝入物品 i, i+1, ... 5 能達到的最大價值。

最優收益函式轉移方程:

\begin{equation}\mathop{f}\limits_{c_{i}x_{i}\leq S_{i}}(S_{i})= \begin{cases} v_{i}x_{i}+f(S_{i+1})\quad &i=1,2,\dots 4\\ v_{i}x_{i}\quad &i=5 \end{cases}\end{equation}

得到最優轉移方程時,就可以求解了。從上式可以看出要用逆推法求解。當然也可以用順推法求解,不過需要改變最優收益函式的定義。

動態規劃求解時,都可以用矩陣來遞推。

用了一位的前輩的圖: http://blog.csdn.net/mu399/article/details/7722810。 我稍微改了下,不是0-1 揹包,每類物品可以裝多個。

這個圖畫的真不錯!只是少了一列,s=0 的一列。

name weight value 1 2 3 4 5 6 7 8 9 10
a 2 6 0 6 6 12 12 18 18 24 24 30
b 2 3 0 3 3 6 6 9 9 12 12 15
c 6 5 0 0 0 6 6 6 6 12 12 12
d 5 4 0 0 0 6 6 6 6 12 12 12
e 4 6 0 0 0 6 6 6 6 12 12 12

最優解是裝入 5 個物品 a !

matlab 程式碼:

function Knapsack
c=[2 2 6 5 4];v=[6 3 5 4 6];
f=zeros(5,11);x=zeros(5,11);xx=zeros(5,1);
for i=5:-1:1
    for S=0:10
        if i==5
            f(i,S+1)=v(i)*floor(S/c(i));
            x(i,S+1)=floor(S/c(i));
        else
            xMax=floor(S/c(i));
            ff=zeros(xMax+1,1);
            for k=0:xMax
                ff(k+1)=v(i)*k+f(i+1,S-c(i)*k+1);
            end
            [f(i,S+1),index]=max(ff);
            x(i,S+1)=index-1;
        end
    end
end
[optValue,index]=max(f(1,:));
xx(1)=x(1,index);
tempS=index;
fprintf('optimal solution:%d\n',optValue);
for i=2:5
    xx(i)=x(i,tempS-c(i-1)*xx(i-1));
    tempS=tempS-c(i-1)*xx(i-1);
end
for i=1:5
    fprintf('put %d item%d in the bag\n',xx(i),i);
end

end



輸出結果:

optimal solution:30
put 5 item1 in the bag
put 0 item2 in the bag
put 0 item3 in the bag
put 0 item4 in the bag
put 0 item5 in the bag

c ++ 程式碼:

用到了動態陣列,以及能夠返回一個數組的函式。

#include"stdio.h"
#include"stdlib.h"


int * Max(int *arr, int n)
{
	int *a=(int *)malloc(2*sizeof(int));
	a[0]=0;a[1]=0;
	for (int i=0;i<n;i++)
	{
		if (arr[i]>a[0])
		{
			a[0]=arr[i];a[1]=i;
		}
	}
	return a;
}

void main()
{
	static const int c[5]={2,2,6,5,4};
	static const int v[5]={6,3,5,4,6};

	int f[5][11];
	int x[5][11];
	int itemNum[5];

	for (int i=5;i>0;i--)
		for (int S=0;S<11;S++)
		{
			if (i==5)
				{
					f[i-1][S]=v[i-1]*(S/c[i-1]);
					x[i-1][S]=S/c[i-1];
				}
			else
			{
				int xMax=S/c[i-1];
				int * ff= (int *)malloc(sizeof(int)*(xMax+1));
				for(int k=0;k<=xMax;++k)
					ff[k]=v[i-1]*k+f[i][S-c[i-1]*k];
				int *a=Max(ff,xMax+1);
				f[i-1][S]=a[0];x[i-1][S]=a[1];
				free(a);
				free(ff);
			}
		}

	int *temp=f[0];
	int *maxValue=Max(temp,11);
	int tempS=maxValue[1];
	itemNum[0]=x[0][tempS];
	for (int i=1;i<5;++i)
	{
		itemNum[i]=x[i][tempS-c[i-1]*itemNum[i-1]];
		tempS-=c[i-1]*itemNum[i-1];
	}
	printf("the optimal solution is: %d\n",maxValue[0]);
	for(int i=0;i<5;i++)
		printf("put %d item%d in the bag\n",itemNum[i],i+1);
	free(maxValue);	
}