何爲0/1揹包問題:
0/1揹包爲一種特殊的揹包問題,一個固定容量C的揹包要裝N種物品,每種物品只有一個,每種物品重量和價值都不相同,且只能選擇裝進去或者不裝進去(即選擇0或者1,無法只裝一部分),要使揹包中的物品價值最大,此爲0/1揹包問題。
具體問題描述:
存在一個容量爲10的揹包,有5種物品,分別重2,2,6,5,4千克,價值分別是6,3,5,4,6元,選擇方案使揹包中物品的總價值最大。
動態規劃解題思路:
動態規劃與貪心都把大問題分解爲小問題,但會不斷記錄前面求解出的結果用於後面的求解,從而減少了時間。動態規劃的核心在於遞推,所以要找到合適的遞推公式,並且建立表格填表,把遞推公式循環完畢即求出問題的答案。
在0/1揹包問題的,一個物品只有裝與不裝兩種選擇,這時候,就出現了兩種情況:
(1)已經裝了i-1個物品,要裝第i個物品,但包裝不下了,此時MaxValue[i][j] = MaxValue[i-1][j],其中j表示揹包容量;
(2)要裝第i個物品,包容量也夠,要判斷裝下這個物品是否滿足最優解,此時判斷公式爲:
MaxValue[i][j] = max{(MaxValue[i-1][j-Weight[i]] + Value[i]) , MaxValue[i-1][j]},即裝與不裝哪個價值大。
01揹包問題代碼實現:
準備了二維數組來作爲輸出結果的存儲:
#define Num 5 //物品數量
#define Cap 10 //揹包容量
int V[Num+1] = { 0,6,3,5,4,6 }; //揹包物品價值
int W[Num+1] = { 0,2,2,6,5,4 }; //揹包物品重量
int M[Num + 1][Cap + 1] = { 0 }; //結果數組
//01揹包動態規劃
void KnaspsackProblem(int *v,int *w)
{
int i, j; //用於循環
for (i = 1; i <= Num; i++)
{
for (j = 1; j <= Cap; j++)
{
if (j < w[i])
{
M[i][j] = M[i - 1][j];
}
else
{
int temp1 = M[i - 1][j];
int temp2 = M[i - 1][j - w[i]] + v[i];
M[i][j] = temp1 > temp2 ? temp1 : temp2;
}
}
}
}
結果與分析:
int main()
{
KnaspsackProblem(V, W);
for (int i = Num; i >0; i--)
{
for (int j = 1; j <= Cap; j++)
{
cout << M[i][j] << "\t";
}
cout << endl;
}
return 0;
}
輸出爲:
i/j 1 2 3 4 5 6 7 8 9 10
5 0 6 6 9 9 12 12 15 15 15
4 0 6 6 9 9 9 10 11 13 14
3 0 6 6 9 9 9 9 11 11 14
2 0 6 6 9 9 9 9 9 9 9
1 0 6 6 6 6 6 6 6 6 6
即最大價值爲15。
何爲矩陣乘法鏈:
矩陣之間可以進行乘法操作,但必須滿足Apq * Bmn中的A矩陣的列數等於B矩陣的行數,即q = m時,此時相乘得到的矩陣C的大小爲p*n,其相乘次數爲p*q*n。
具體問題描述:
給定n個矩陣構成的一個鏈<A1,A2,A3,.......An>,其中i=1,2,...n,矩陣A的維數爲pi-1pi,對乘積 A1A2...An 以一種最小化標量乘法次數的方式進行加全部括號。
動態規劃解題思路:
遞推方程爲:
i ==j時 ,m[i][j] = 0 ;
i < j時,m[i][j] = min{m[i,k]+m[k+1,j]+pi-1-1*pk*pj。
矩陣乘法鏈代碼實現:
#define N 10
//矩陣乘法鏈
void MatrixChain(int *p,int (*m)[N],int (*t)[N],int length)
{
int n = length - 1; //矩陣數量
int i, j,k;//用於循環
int s,num;
//當i=j時,只有一個矩陣,相乘次數爲0
for (i = 1; i < length; i++)
{
m[i][i] = 0;
}
for (i = 2; i < length; i++)
{
for (j = 1; j < n - i + 1; j++)
{
s = j + i - 1;
m[j][s] = 0x7fffffff; //爲無窮值
for (k = j; k <= s - 1; k++)
{
num = m[j][k] + m[k + 1][s] + p[j - 1] * p[k] * p[s];
if (num < m[j][s])
{
m[j][s] = num;
t[j][s] = s;
}
}
}
}
}
//打印結果
void OutputResult(int(*t)[N], int i, int j)
{
if (i == j)
{
cout << "A" << i;
}
else
{
cout << "(";
OutputResult(t, i, t[i][j]);
OutputResult(t, t[i][j] + 1, j);
cout << ")";
}
}