动态规划算法设计分为两步
把原始问题分解成子问题,这里和分治法对于子问题的处理方式不同,分治法是将原问题分解成子问题后递归求解,而动态规划算法对于每个子问题仅求解一次
自底向上的计算
使用动态规划的条件
存在优化子结构
存在重叠子问题
优化子结构可以简单的理解为,将问题拆分后自底向上计算,而每一个高一级母问题对应的低一级子问题都是最优的。
重叠子问题及是在自底向上的计算过程中存在重复的问题,为了避免重复,因此才具备了优化的必要。
具体步骤
分析优化解的结构,确定是否适用于动态规划。
递归的定义计算最优解的代价(每个子问题仅计算一次)
自底向上的计算优化解的代价并保存,获取结构最优解的信息
根据结构最优解的信息构建最优解,下面以具体事例说明
矩阵链乘法
A1*A2*……….An (A为矩阵)
由于矩阵具有交换律,且由于矩阵乘法的特定,以不同的顺序进行矩阵链的乘法计算的复杂度是差别极大的,因此有必要找到一个最优的计算顺序。下面以一个n为4的矩阵链为例:
假设 A1=10*50 A2=50*5 A3=5*10 A4=10*5
T(((A1A2)A3)A4)=10*50*5+10*5*10+10*10*5=2500+500+500=3500
T((A1A2)(A3A4)=…….=3000
T((A1(A2A3))A4)=…….=3500
T(A1((A2A3)A4))=…….=6250
T((A1A2)(A3A4)=…….=3000
T(A1(A2(A3A4)))=…….=4000
定义两个记号 Ai-j=Ai*Ai+1*……….A*j
cost( Ai-j)=计算 Ai-j的代价
若计算Ai-j的优化顺序在k处断开 Ai-n= Ai-k* Ak+1-n
则在Ai-n的优化顺序中,对应子问题 Ai-k和Ak+1-n亦是优化解,而因为计算的过程是自底向上的,所以每一次计算得到并储存的结果都是优化解,这样该问题就满足了优化子结构的条件,接下来再看一下是否具有重叠子问题
从上图我们可以清楚的发现存在重叠子问题,因此就可以用动态规划算法求解。
假设 m【i,j】=计算Ai-j的最小乘法数(在实际算法中此处包含较多信息故使用的结构体存储)
m【1,n】=计算A1-n的最小乘法数
m【i,j】=0 i=j
m【i,j】=min(i《k《j){m【i,k】+m【k+1,j】+p(m【i,k】与m【k+1,j】相乘的代价)}
数据存储使用动态分配的二维结构体数组
可以按照这个样子从左下向右上存储,画图好丑。。。。。。
代码如下
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#define LEN sizeof(struct Matrix)
struct Matrix *p;
int len;
struct Matrix_Mul **a;
struct Matrix
{
int serial;
int row;
int coloum;
};
struct Matrix_Mul
{
int cost;
int ans_row;
int ans_coloum;
};
void Matrix_input()
{
int i;
printf("请输入矩阵的个数:\n");
scanf_s("%d", &len);
p = (struct Matrix *)malloc(len*LEN);
printf("输入矩阵的属性,输入行和列:\n");
for (i = 0; i<len; i++)
{
p[i].serial = i + 1;
printf("第%d个矩阵:", p[i].serial);
scanf_s("%d %d", &p[i].row, &p[i].coloum);
}
}
int min_cost(int *array, int k)
{
int cost,min=0,i,j;
for ( i = 0; i < k; i++)
{
if (array[min] > array[i]) //找出最小值的位置
{
min = i;
}
}
return min;
}
struct Matrix_Mul Sub_structure(struct Matrix *p, int i, int j)
{
int k,f=0;
int *choose, *choose_r, *choose_c;
choose = (int *)malloc(j-i);
choose_r = (int *)malloc(j - i);
choose_c = (int *)malloc(j - i);
if (i==j)
{
a[i][j].cost = 0;
a[i][j].ans_row = p[i].row;
a[i][j].ans_coloum = p[i].coloum;
}
else
{
for (k = i; k < j; k++)
{
choose[f] = a[i][k].cost + a[k + 1][j].cost + a[i][k].ans_row*a[i][k].ans_coloum*a[k+1][j].ans_coloum;
choose_r[f] = p[i].row;
choose_c[f] = p[j].coloum;
f++;
}
k = j - i;
f = min_cost(choose, k);
a[i][j].cost = choose[f];
a[i][j].ans_row = choose_r[f];
a[i][j].ans_coloum = choose_c[f];
}
}
int matrix_chain(struct Matrix *p)
{
int i = 0, j = 0 ,k,result;
a = (int **)malloc(sizeof(int *)* len);//generating len*len dyadic
for (j = 0; j < len; j++)
{
a[j] = (int *)malloc(sizeof(int)* len);
}
for (k = 0; k < len; k++)
{
for (i = 0,j=k; i < len - k; i++, j++)
{
Sub_structure(p, i,j);
}
}
return a[0][len - 1].cost;
}
int main()
{
int i,min;
Matrix_input();
min = matrix_chain(p);
//printf("数组输出:\n");
//for (i = 0; i<len; i++)
//{
// printf("%4d%4d%4d\n", p[i].serial, p[i].row, p[i].coloum);
//}
printf("The min cost id %d\n", min);
system("pause");
return 0;
}
运行结果