首页 > 其他 > 详细

三角形问题

时间:2016-01-02 01:02:56      阅读:295      评论:0      收藏:0      [点我收藏+]

算法目的

有一个数字三角形,现从顶点出发,在每个节点可以选择向左走或者向右走,一直走到底层。现设计一种算法,计算出从三角形顶端到底部的一条路径,是该路径经过的数字总和最小。

编码软件

Dev_c++

算法思想

此问题采用动态规划思想解决。

  1. 最优子结构

    数字三角形采用一个二维数组init[][]存储,第一行的数字存在init[0][0],第二行的数字存在init[1][0]和init[1][1],第三行的数字存在init[2][0]、init[2][1]和init[2][2],所以第i行的数字存储在数组init[i-1][0]至init[i-1][i-1]。

    现计算路径的数字总和status[][],由题意知,要到达第三行的数字必须经过第二行和第一行,即要到达init[2][0]的总和status[2][0]则需计算到达init[1][0]的数字总和status[1][0],要到达init[2][1]则需计算min{到达init[1][0]的数字总和status[1][0],到达init[1][1]的数字总和status[1][1]},要到达init[2][2]则需计算到达init[1][1]的数字总和status[1][1]。

    由此可知若要到达init[k][0]的元素只需计算到达init[k-1][0]的数字总和status[k-1][0],

    要到达init[k][k]的元素只需计算到达init[k-1][k-1]的数字总和status[k-1][k-1],

    要到达init[2…k-1][1…k-1]的元素则需计算min{到达init[1…k-2][0…k-1]的数字总和status[1…k-2][0…k-1],到达init[1…k-2][1…k-1]的数字总和status[1…k-2][1…k-1]}。

  2.  递归求解方案

    初始化status[][]数组时赋值10000,而构成数字三角形的数值都不会超过100且规定最大行数为50,即max{status[k][k]}<10000,由此要到达init[k][k]的元素就需计算min{到达init[k-1][k-1]的数字总和status[k-1][k-1],到达init[k-1][k]的数字总和status[k-1][k]}。再由(1)总结得

    status[i][j]=status[i-1][0]+init[i][0] ( j=0 )

    or min{status[i-1][j-1],status[i-1][j]}+init[i][j] ( j!=0)

  3. 计算最优代价

    根据计算status[i][j]的递归式,可以写出一个迭代的算法进行计算,并在计算过程中保存已解决的子问题答案,每个子问题计算一遍,在后面需要时只需简单地进行查表,其中Road[][]记录路径信息。

    算法如下:

    Algorithms countStatus(init[][],status[][],Road[][],num)

        For i 0 to num    //行数

            For j 0 to i    //列数

                If i==0&&j==0

                    status[i][j] = init[i][j]

                else if i!=0&&j==0                 //到达init[k][0]的情况

                    status[i][j] = status[i-1][j]+init[i][j];

                    Road[2*i-1][j] = ‘|‘

                Else if status[i-1][j]>status[i-1][j-1]        //到达init[k][k]

                    status[i][j] = init[i][j]+status[i-1][j-1];

                    Road[2*i-1][2*j-1] = ‘\\‘

                Else

                    status[i][j] = init[i][j]+status[i-1][j];

                    Road[2*i-1][2*j] = ‘|‘

  4.  构造最优解

    找出min(status[i][0…i]),假设是status[i][j],再根据status[i-1][j-1]和status[i-1][j]判断status[i][j]是从左边来的还是从右边来的,将方向信息记录在Road_sign[][]中,结束后只输出到达status[i][j]的路径。

    Algorithms path(status[][],Road_sign[][])

        min = status[num-1][0]

        k=0;

        for j=1 to num

            if(min>status[num-1][j])

                min = status[num-1][j];         //最小的代价

                k=j;

        for i=num-1 to 0

            if(k == 0) //若最小的元素是status[i][0]

                Road_sign[2*i-1][0] = 1;          //输出标记

            else if(k == i)                    //若最小的元素是status[i][i]

                Road_sign[2*i-1][2*i-1] = 1;

                k = k-1;                       //通过init[i-1][i-1]到达

            else //若最小的元素是status[i][1…i-1]

                if(status[i-1][k]>status[i-1][k-1])

                    Road_sign[2*i-1][2*k-1] = 1;

                    k = k-1;                  //通过init[i-1][i-1]到达

                else

                    Road_sign[2*i-1][2*k] = 1;

        For i=0 to 2*num-1           //输出最优路径

            For j=0 to i

                if(i%2 == 0)

                    printf("%3c",Road[i][j]);

                else

                    if(Road_sign[i][j] == 1)

                        printf("%3c",Road[i][j]);

c语言代码描述

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


int main(int argc, char *argv[]) {
    int init[50][50],status[50][50];
    char Road[100][100];
    int Road_sign[100][100];
    int i,j,k,num,min;

    printf("请输入三角形的层数:");
    scanf("%d",&num);

    for(i=0; i<num; i++) {
        for(j=0; j<num; j++) {

            status[i][j] = 10000;

        }
    }

    //产生随机数 
    srand((unsigned)time(NULL));

    for(i=0; i<num; i++) {
        for(j=0; j<=i; j++) {

            init[i][j] = rand()%100;

        }
    }
    //初始化方向信息数组 
    for(i=0; i<2*num; i++) {
        for(j=0; j<2*num; j++) {
            if(i%2==0 && j%2==0) {
                Road[i][j] = o;
            } else {
                Road[i][j] =  ;
            }
            Road_sign[i][j]=0;
        }
    }
    //输出数值三角形 
    for(i=0; i<num; i++) {
        for(j=0; j<=i; j++) {

            printf("%4d",init[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");
                    //计算出从三角形顶端走到底部的最小值,以及保存路径信息 
    for(i=0; i<num; i++) {
        for(j=0; j<=i; j++) {

            if(i==0 && j==0) {

                status[i][j] = init[i][j];    //到达顶点 

            } else if(j==0 && i!=0) {    //到达init[k][0]的情况 

                status[i][j] = status[i-1][j]+init[i][j];
                Road[2*i-1][j] = |;    //只能通过init[k-1][0]到达 

            } else if(status[i-1][j]>status[i-1][j-1]) {    //到达init[k][k]的情况 

                status[i][j] = init[i][j]+status[i-1][j-1];
                Road[2*i-1][2*j-1] = \\;    //通过init[k-1][k-1]到达 

            } else {

                status[i][j] = init[i][j]+status[i-1][j];
                Road[2*i-1][2*j] = |;        //通过init[k-1][k]到达 

            }

        }
    }

//构造最优解
 
    min = status[num-1][0];
    k=0;
    for(j=1; j<num; j++) {
        if(min>status[num-1][j]) {
            min = status[num-1][j];    //确定最优解 
            k=j;
        }
    }


        //标记要输出的最优路径 
    for(i=num-1; i>0; i--) {
        if(k == 0) {
            Road_sign[2*i-1][0] = 1;
        } else if(k == i) {
            Road_sign[2*i-1][2*i-1] = 1;
            k = k-1;    //通过左上方到达 
        } else {
            if(status[i-1][k]>status[i-1][k-1]) {
                Road_sign[2*i-1][2*k-1] = 1;
                k = k-1;    //通过左上方到达 
            } else {
                Road_sign[2*i-1][2*k] = 1;    //通过上方到达 
            }
        }
    }

//输出到达各点的代价 
    for(i=0; i<num; i++) {
        for(j=0; j<=i; j++) {

            printf("%4d",status[i][j]);
        }
        printf("\n");
    }

    printf("\n");
    /*    for(i=0; i<2*num-1; i++) {
            for(j=0; j<=i; j++) {
                printf("%2d",Road_sign[i][j]);
            }
            printf("\n\n");
        }
    */
//输出最优路径 
    for(i=0; i<2*num-1; i++) {
        for(j=0; j<=i; j++) {

            if(i%2 == 0) {
                printf("%3c",Road[i][j]);
            } else {

                if(Road_sign[i][j] == 1) {
                    printf("%3c",Road[i][j]);
                } else {
                    printf("   ");
                }

            }

        }
        printf("\n");
    }

    return 0;
}

时间复杂性

整个程序的计算量主要集中在算法countStatus()中的i 和 j 的两重循环中。循环体内的计算量为O(1),而2重循环的总次数为O(n2)。因此,该算法的计算时间上界为O(n2)。

程序截图

技术分享

Status[][]数组

技术分享

最优的路径

技术分享

三角形问题

原文:http://www.cnblogs.com/sillypasserby/p/5093982.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!