动态规划算法

Posted on 2019-12-23 14:33  金色的省略号  阅读(302)  评论(0编辑  收藏  举报

  将递归算法重新写成非递归算法让后者,把那些子问题的答案,系统地记录在一个表内利用这种方法的一种技巧称为动态规划( dynamic programming )

  一、斐波那契数列

  递归算法

# include <stdio.h>
#include <string.h>

int Fab(int n)
{ 
    if ( n <= 1 )
        return 1;
    else
        return Fab( n-1 )+Fab( n-2 );
}

int main()
{
    int n;
    scanf("%d",&n);

    printf("%d\n",Fab(n));

    return 0;
}
View Code

  非递归算法

# include <stdio.h>
#include <string.h>

int Fab(int n)
{ 
    if ( n <= 1 )
        return 1;
    int last = 1;
    int nextToLast = 1;
    int answer = 1;
    for(int i = 2; i<=n; i++)
    {
        answer = last + nextToLast;
        nextToLast = last;
        last = answer;
    }
    return answer;
}

int main()
{
    int n;
    scanf("%d",&n);

    printf("%d\n",Fab(n));

    return 0;
}
View Code
# include <stdio.h>
#include <string.h>
# define N 100

int fab[N] = {1,1};
void Fab(int n)
{
    for(int i=2; i<=n; ++i){
        fab[i] = fab[i-1] + fab[i-2];
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    Fab(n);

    for(int i=0; i<=n; ++i)
        printf("%d ",fab[i]);
    
    return 0;
}
View Code

  二、多源最短路径(给定带权有向图(G = (V,E)),求任意两顶点(Vi,Vj)之间的最短路径)

  弗洛伊德算法(Floyd),动态规划思想,算法复杂度大O(N的三次方)。

  算法步骤:

  1、先定义一个n阶的矩阵,令其对角线的值为0,若存在弧,则对应元素为弧值,否则为无穷大

  2、逐步在原直接路径中增加中间顶点,若加入中间顶点后,路径变短,则修改之,否则维持

  3、所有顶点试探完毕,算法结束。

#include <stdio.h>
#include<stack>
#define N 4
#define MAXINT 1000
int main()
{
    //#ifndef N
    int i,j,k;
    /*
       1.A数组, 存储顶点之间弧值,对角线值为0,
       顶点之间存在弧,存弧值,否则弧值MAXINT
    */
    int A[N][N] = {   0,      5,      MAXINT,  7,
                      MAXINT, 0,      4,       2,
                      3,      3,      0,       2,
                      MAXINT, MAXINT, 1,       0
                  };

    /* 2.D数组\Path数组赋值 */
    int D[N][N];    //Vi到Vj的最短路径长度
    int Path[N][N]; //Vi到Vj的最短路径

    for(i=0; i<N; ++i)
    {
        for(j=0; j<N; ++j)
        {
            /* D数组赋值 */
            D[i][j] = A[i][j];
            /* Path数组赋值 */
            if(i!=j && A[i][j] < MAXINT)
                Path[i][j] = i;
            else
                Path[i][j] = -1;
        }
    }

    /* 3.计算最短路径长度及最短路径 */
    //加入k顶点的最短路径长度
    //D[i][j] = min(D[i][j], D[i][k] + D[k][j]);
    for(k=0; k<N; k++)
    {
        for(i=0; i<N; i++)
        {
            for(j=0; j<N; ++j)
            {
                if(D[i][k]+D[k][j] < D[i][j]){
                    D[i][j] = D[i][k] + D[k][j];
                    Path[i][j] = Path[k][j];
                }
            }
        }
    }
    //#endif

    /* 4.打印最短路径长度 */
    for(i=0; i<N; ++i){
        for(j=0; j<N; ++j)
            printf("%5d",D[i][j]);
        printf("\n");
    }
    printf("\n");
    /*
        0  5  8  7
        6  0  3  2
        3  3  0  2
        4  4  1  0
    */

    /* 5.打印最短路径路径 */
    for(i=0; i<N; ++i){
        for(j=0; j<N; ++j)
            printf("%5d",Path[i][j]);
        printf("\n");
    }
    printf("\n");
    /*
       -1  0  3  0
        2 -1  3  1
        2  2 -1  2
        2  2  3 -1
    */

    /* 6.打印顶点1到顶点0的最短路径 */
    int v1 = 1,v0 = 0;

    /* int arr[N] = {v0}, index = 1;
    while(Path[v1][v0] != -1){
        arr[index++] = v0 = Path[v1][v0];
    }

    for(int i=index-1; i>=0; --i){
        if(i != index-1) printf(" ->");
        printf(" %d",arr[i]);
    }*/
    /* 1 -> 3 -> 2 -> 0 */

    printf("%5d",v0);
    while(Path[v1][v0] != -1)
    {
        printf(" <- %d",Path[v1][v0]);
        v0 = Path[v1][v0];
    }
    printf("\n");
    /* 0 <- 2 <- 3 <- 1 */
    return 0;
}
View Code