【记忆化搜索】 数字三角形最佳路径

题目描述:

给你一个数字三角形, 形式如下:
        2
    10   5  
   4   3   6  
 1   8   7   9  
找出从第一层到最后一层的一条路,使得所经过的权值之和最小或者最大

 

算法1:

从顶到底层记忆每一步;

#include<iostream>
#define N 50
using namespace std;
int Max=0;

void fun(int a[N][N],int n,int k,int v,int sum){
	if(k==n){
		Max=sum>Max?sum:Max;
		cout<<"n = "<<n<<"  max = "<<Max<<endl;
		return ;
	}
	else{
		//cout<<"sum="<<sum<<endl;
		int sum1=sum+a[k+1][v];
		int sum2=sum+a[k+1][v+1];
		fun(a,n,k+1,v,sum1);       //分支
		fun(a,n,k+1,v+1,sum2);
	}
	return ;
}

int main(){
	int array[N][N];
	int n,m;
	while(cin>>n){       //输入三角形的行数
		for(int i=0;i<n;i++){          //输入三角形数据
			for(int j=0;j<=i;j++){ 
				cin>>m;
				array[i][j]=m;
			}
		}
		for(int i=0;i<n;i++){          //输出三角形数据
			for(int j=0;j<=i;j++){
				cout<<array[i][j]<<" ";
			}
			cout<<endl;
		}
		fun(array,n,0,0,array[0][0]);     //传参调用
		cout<<"the max is "<<Max<<endl;
	}
	return 0;
}

 

注意:在分支的时候不能对比左右两步的大小来分支,也就是说不能每一次都选择最大的那一步,否则算出的结果并非是全局性的。因此这个算法的复杂度不低。所以需要算法2

 

算法2:

从底层到顶,每一步都通过比较下一层的左右两个元素来取大的记录。

#include<iostream>
#include<algorithm>
#define N 50
using namespace std;
int a[N][N];
int p[N][N];
int num;

int fun(int i,int j){
	if(p[i][j]!=0){        //如果该值被记录过,则直接返回
		return p[i][j];
	}
	if(i==num-1){          //如果到达了最底层,则返回底层元素
		return p[i][j]=a[i][j];
	}
	return p[i][j]=a[i][j]+max(fun(i+1,j),fun(i+1,j+1));    //比较下一层的左右两个元素,择最大的保存为当前位置的值
}
int main(){
	int n,m;
	while(cin>>n){
		for(int i=0;i<n;i++){
			for(int j=0;j<=i;j++){
				cin>>m;
				a[i][j]=m;
			}
		}
		for(int i=0;i<n;i++){
			for(int j=0;j<=i;j++){
				cout<<a[i][j]<<" ";
			}
			cout<<endl;
		}
		num=n;
		cout<<fun(0,0)<<endl;
	}
	return 0;
}

 

点赞