您的位置:首页 > 其它

0/1背包问题与矩阵乘法链(动态规划)

2018-01-28 02:59 302 查看
何为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)
,int (*t)
,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)
, 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 << ")";
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息