数字三角——递归、递归、内存搜索

数字三角

叙述性说明:

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

问题:

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

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

分析:

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

假设用回溯法求出全部的可能的路线,就能够从中选出最优的路线。但和往常一样,回溯法的效率太低:一个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\n",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\n",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\n",distance(1,1));
	}
	return 0;
}
 

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

时间: 2024-11-06 03:50:17

数字三角——递归、递归、内存搜索的相关文章

MongoDB学习笔记~大叔框架实体更新支持N层嵌套~递归递归我爱你!

回到目录 递归递归我爱你!保要你想做,就一定能成功! 从一到二,从二到三,它是容易的,也是没什么搞高的,或者说,它是一种流水线的方式,而从三到十,它注定要有一个质的突破,否则,它会把你累死,代码写的让你自己都觉得想吐!有时,我们是被逼出来的,对于一种功能的实现,我们有时需要有从三到十的态度…… 回归回实例,在mongodb中实体可以嵌套,这在C#里叫做复杂属性,即类中也有类级的属性,这在面向对象里叫做“组合”,它经常在日常开发环境中见到,大家都耳熟能详了,呵呵,而在mongodb里,如果希望对N

SCU - 1114 数字三角

下图是个数字三角,请编写一个程序计算从顶部至底部某处一条路径,使得该路径所经过的数字总和最大. 7 3  8 8  1  0 2  7  4  4 1.  每一步可沿左斜线向下或右斜线向下走: 2.  1<=三角形行数<=100 3.  三角形中的数字为整数 0,1,--,99. 4.  如果有多种情况结果都最大,任意输出一种即可. 输入: 第一行一个整数N,代表三角形的行数. 接下来N行,描述了一个数字三角. 输出: 第一行一个整数,代表路径所经过底数字总和. 第二行N个数,代表所经过的数字

动态规划 数字三角形(递归,递推,记忆化搜索)

题目要求: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 在上面的数字三角形中寻找在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大.路径上的每一步都只能往左下或右下走.只需要求出这个最大和即可,不必给出具体路径. 三角形的行数大于1小于等于100,数字为 0 - 99 输入格式: 5 //三角形行数.下面是三角形 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 解题思路: 用二维数组存放数字三角形 D[r][j] //表示第i行第j个元素的

动态规划&mdash;&mdash;数字三角形(递归or递推or记忆化搜索)

动态规划的核心就是状态和状态转移方程. 对于该题,需要用抽象的方法思考,把当前的位置(i,j)看成一个状态,然后定义状态的指标函数d(i,j)为从格子出发时能得到的最大和(包括格子本身的值). 在这个状态定义下,原问题的解就是d(i,j). 下面看一下不同状态之间如何转移.从格子(i,j)出发有两种策略.如果向左走,则到(i+1,j)后需要求"从(i+1,j)出发能得到的最大和"这一问题,即d(i+1,j). 类似的,往右走之后需要求解d(i+1,j+1).由于可以在这两个决策中自由选

递归之深度优先搜索

递归的思想在写程序中运用较为广泛,看视很复杂的问题,通常通过递归思想找出"递归结构",分解成重复的小步骤即可解决,但是递归的思想有时并不好理解(大佬,悟性高的忽略).本文通过介绍全排序例子介绍递归思想,最后给出前一次博客写的"坑爹的奥数"问题进行递归优化,给出执行时间. 一.问题描述:假如有编号为1.2.3的3张扑克牌和编号为1.2.3的3个盒子.现在需要将这3张扑克牌分别放到3个盒子里面,并且每个盒子有且只有一张扑克牌.那么一共有多少种不同的放法呢? 当有n个数字

递归和内存分配(可视化)

每一次递归调用都将过程(精确地说是"变量")在内存中复制一遍.一旦一个过程结束(会返回一些数据),这个过程在内存中的副本就被丢弃.递归看似简单,但是可视化跟踪执行过程就很花费时间.好了,让我们来看下面的例子: int Print(int n) //print numbers 1 to n backwards { if(n == 0) return 0; else { printf("%d",n); return Print(n-1); //recursive cal

Java基础------杨辉三角(递归实现)

  第一列 第二列 第三列 第四列 第五列 第六列 第七列 第八列 第九列 第十列 第十一列 ...... 第一行 第一个空格  第二个空格  第三个空格  第四个空格 第五个空格 1             第二行 第一个空格 第二个空格  第三个空格 第四个空格 1   1           第三行 第一个空格 第二个空格  第三个空格 1   2   1         第四行 第一个空格 第二个空格 1   3   3   1       第五行 第三个空格 1   4   6   4

C输出帕斯卡三角(杨辉三角)递归实现

1 /*帕斯卡三角形(杨辉三角)*/ 2 int Recursive_Pascal_Triangle( int i, int j ) 3 { 4 if( (j == 0) || (i == j) ) 5 return 1; 6 else{ 7 return Recursive_Pascal_Triangle(i-1,j-1) + Recursive_Pascal_Triangle( i-1, j ); 8 } 9 } 10 11 /*输出三角形*/ 12 void display_triangl

由数字三角问题来理解DP

先看几类数字三角形的问题,通过对这几个问题的分析来理解有关动态规划的基本思想 数字三角形I 问题描述: 有一个由正整数组成的三角形,第一行只有一个数,除了最下行之外 每个数的左下方和右下方各有一个数,从第一行的数开始,每次可以往左下或右下走一格,直到走到三角形底端,把沿途经过的数全部加起来作为得分.如何走,使得这个得分尽量大? 分析: 如何走,是一个决策问题,很容易联想到一种贪心策略是:每次选数字大的那个方向走.然而很明显,这种决策方案是错误的.因为如果按这种方案,得到的结果是1→3→10→3,