算法初探——动态规划

动态规划算法设计分为两步
把原始问题分解成子问题,这里和分治法对于子问题的处理方式不同,分治法是将原问题分解成子问题后递归求解,而动态规划算法对于每个子问题仅求解一次
自底向上的计算

使用动态规划的条件
存在优化子结构
存在重叠子问题
优化子结构可以简单的理解为,将问题拆分后自底向上计算,而每一个高一级母问题对应的低一级子问题都是最优的。
重叠子问题及是在自底向上的计算过程中存在重复的问题,为了避免重复,因此才具备了优化的必要。

具体步骤
分析优化解的结构,确定是否适用于动态规划。
递归的定义计算最优解的代价(每个子问题仅计算一次)
自底向上的计算优化解的代价并保存,获取结构最优解的信息
根据结构最优解的信息构建最优解,下面以具体事例说明

矩阵链乘法
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】相乘的代价)}

数据存储使用动态分配的二维结构体数组
算法初探——动态规划_第1张图片
可以按照这个样子从左下向右上存储,画图好丑。。。。。。
代码如下

#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;
}

运行结果

你可能感兴趣的:(算法,动态规划)