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;
}
}
}
}
}
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 << ")"; } }
相关文章推荐
- 动态规划-背包问题(状态转换)
- 动态规划之0/1背包问题-java实现
- H - Piggy-Bank (动态规划)(完全背包问题)
- [PKU暑课笔记] 动态规划(三) 最佳加法表达式 百练2755 POJ3624背包问题
- 动态规划 4、基础背包问题总结(多重背包与多重背包的转化)
- 学习日志---动态规划(背包问题)
- 0-1背包问题与完全背包问题C++实现 动态规划
- 动态规划小结——背包问题
- 014-背包问题-动态规划-《算法设计技巧与分析》M.H.A学习笔记
- [Sicily Coins] 动态规划 多重背包问题
- 【集训笔记】动态规划背包问题【HDOJ1421【HDOJ1058【HDOJ2546
- 算法导论16.2-2--动态规划(0-1背包问题)
- 【动态规划】常见背包问题合集
- 0-1背包问题与完全背包问题C++实现 动态规划
- 算法导论--动态规划(0-1背包问题)
- Java 动态规划求解0-1背包问题
- 动态规划——背包问题
- 【动态规划/二维背包问题】mr355-三角形牧场
- 0019算法笔记——【动态规划】0-1背包问题
- 完全背包问题(动态规划)(完全背包)