zoukankan      html  css  js  c++  java
  • 数字三角——递归、递归、内存搜索

    数字三角

    叙述性说明:
             有一个非负整数三角,第一行中只有一个号码,的左下方和右下方各有一个数。

    问题:    
             从第一行的数開始。每次能够往左下或右下走一格。直到走到最下行,把沿途经过的数所有加起来。

    怎样走才干使得这个和尽量大?


    分析:

           不难看出此题是一个动态的决策问题:每次有两种选择——左下或右下。

    假设用回溯法求出全部的可能的路线,就能够从中选出最优的路线。但和往常一样,回溯法的效率太低:一个n层数字三角形的完整路线有2^n条。当n非常大时回溯法的速度将让人无法忍受。因此本题讨论用递归,递推及记忆化搜索的方法实现,尽管还有其它的方法,但此时仅仅讨论学习比較相似的这几种方法。



    最先想到的是递归实现:

    #include "stdio.h"
    #define maxn 100
    int a[maxn][maxn],n;
    
    inline max(int x,int y)
    {
    	return x>y?x:y;	
    }
    
    //递归计算实现 
    int d(int x,int y)
    {
    	return a[x][y]+(x==n?

    0:max(d(x+1,y),d(x+1,y+1))); } int main() { while(~scanf("%d",&n)) { int i,j; for(i=1;i<=n;i++){ for(j=1;j<=i;j++) scanf("%d",&a[i][j]); } printf("max:%d ",d(1,1)); } return 0; }

    尽管这样做是正确的,但时间效率太低。其原因在于反复计算。
            例: 在下列计算中d(3,2)被反复调用  

                        d(2,1)   的计算会调用--> d(3,1) , d(3,2)
                        d(2,2)   的计算会调用--> d(3,2) , d(3,3)


    递推的实现:

    #include "stdio.h"
    #define maxn 100
    int a[maxn][maxn],n;
    
    inline max(int x,int y)
    {
    	return x>y?

    x:y; } //递推实现 int d(int x,int y) { int d[n][n],i,j; for(j=1;j<=n;j++) d[n][j]=a[n][j]; for(i=n-1;i>=1;i--){ for(j=1;j<=i;j++) d[i][j]=a[i][j]+max(d[i+1][j],d[i+1][j+1]); } return d[x][y]; } int main() { while(~scanf("%d",&n)) { int i,j; for(i=1;i<=n;i++){ for(j=1;j<=i;j++) scanf("%d",&a[i][j]); } printf("max:%d ",d(1,1)); } return 0; }


    记忆化搜索实现:

    #include "stdio.h"
    #include "string.h" 
    #define maxn 100
    int a[maxn][maxn],n;
    int d[maxn][maxn];	//记忆化搜索所使用的状态记忆数组 
    inline max(int x,int y)
    {
    	return x>y?x:y;	
    }
    
    /*
    	记忆话搜索。程序分成两部分。首先  memset(d,-1,sizeof(d)); 把d所有初始化为-1, 
    然后编写递归函数: 
    */ 
    int distance(int i,int j)
    {
    	if(d[i][j]>=0) return d[i][j];
    	return d[i][j]=a[i][j]+(i==n?0:max(distance(i+1,j),distance(i+1,j+1)));
    } 
    /*
    	上述程序依旧是递归的,但同一时候也把计算结果保存在数组d中。题目中说各个数都是非负的,因此
    假设已经计算过某个d[i][j]。则它应是非负的,这样。仅仅需把所有d初始化为-1,就可以通过推断是否
    d[i][j]>=0得知是否已经被计算过。 
    */ 
    
    
    int main()
    {
    	while(~scanf("%d",&n))	
    	{
    		int i,j;
    		for(i=1;i<=n;i++){
    			for(j=1;j<=i;j++)
    				scanf("%d",&a[i][j]);
    		}
    		memset(d,-1,sizeof(d));	//状态记忆化数组初始化 				
    		printf("max:%d
    ",distance(1,1));							
    	}
    	return 0;
    }
     



    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    gcc编译时头文件和库文件搜索路径
    vim 使用
    stdlib.h stdio.h
    sys/types.h fcntl.h unistd.h sys/stat.h
    gcc 使用
    grep 正则表达式
    firefox
    CentOS7 屏幕亮度的命令行管理
    linuxqq
    rpm 与 yum 源
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4675902.html
Copyright © 2011-2022 走看看