6.1 动态规划:数字三角形

在上面的数字三角形中寻找一条从顶部到底边的路径,使得 路径上所经过的数字之和最大。路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。

输入:

5

3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出:

30 

解析:如果要算第1行第1个数字到底边的最大和,就要先算第2行第1个数字以及第2行第2个数字到底边的最大和;

要算第2行第1个数字到底边的最大和就要第三行第一个和第二个数字到底边的最大和……很明显,这是一个典型的递归问题。

#include<iostream>
#define N 100
using namespace std;
int a[N][N];
int n;
int SumMax(int i, int j)//第i行第j列的数字到底边的最大和 
{
	if(i == n)  return a[i][j];
	else
		return max(SumMax(i+1,j),SumMax(i+1,j+1))+a[i][j];
}
int main()
{
	freopen("a.txt","r",stdin);
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= i; ++j)
		{
			cin >> a[i][j];
		}
	}
	cout << SumMax(1,1);
	return 0;
}

这个代码会超时,因为存在大量的重复计算。比如我们从上往下看,在计算第2行第2个数到底边的最大距离之和时,1这个数字要重复调用2次。第2行第一个数字调用一次,第2行第2个数字又要调用一次。

【改进】 

改进后的代码: 

#include<iostream>
#define N 100
using namespace std;
int a[N][N];
int maxsum[N][N];
int n;
int SumMax(int i, int j)//第i行第j列的数字到底边的最大和 
{
	if(maxsum[i][j] != -1)//要一直调用到第n行才会算出结果,然后再出栈算出结果 
		return maxsum[i][j];
	if(i == n)  maxsum[i][j] = a[i][j];
	else
	{
		int x = SumMax(i+1,j);
		int y = SumMax(i+1,j+1);
		maxsum[i][j] = max(x,y)+a[i][j];
	}
	return maxsum[i][j];
}
int main()
{
	freopen("a.txt","r",stdin);
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= i; ++j)
		{
			cin >> a[i][j];
			maxsum[i][j] = -1;//等于-1说明没有计算过 
		}
	}
	cout << SumMax(1,1);
	return 0;
} 

 用递推的方法解决问题:

#include<iostream>
#define N 100
using namespace std;
int a[N][N];
int n; 
int summax[N][N];
int main()
{
	freopen("a.txt","r",stdin);
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= i; ++j)
		{
			cin >> a[i][j];
		} 
	}
	for(int i = 1; i <= n; ++i)//从最后一行开始递推 
		summax[n][i] = a[n][i];
	for(int i = n-1; i >= 1; --i)
	{
		for(int j = 1; j <= n; ++j)
		{
			summax[i][j] = max(summax[i+1][j],summax[i+1][j+1]) + a[i][j];
		}
	}
	cout << summax[1][1] << endl;
	return 0;
} 

空间优化:

要点:只需要最后一行记录每次的和变化即可,因为不需要求出具体的路径,只需要知道最大和,所以每次用最后一行来更新最大和。

#include<iostream>
#define N 100
using namespace std;
int a[N][N];
int maxsum[N];//求最大和 
int main()
{
	freopen("a.txt","r",stdin);
	int n;
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= i; ++j)
		{
			cin >> a[i][j];
		}
	}
	for(int i = 1; i <= n; ++i)
	{
		maxsum[i] = a[n][i];
	}
	for(int i = n-1; i >= 1; --i)
	{
		for(int j = 1; j <= n; ++j)
		{
			maxsum[j] = max(maxsum[j],maxsum[j+1]) + a[i][j];
		}
	}
	cout << maxsum[1] << endl;
	return 0;
} 

#include<iostream>
#define N 100
using namespace std;
int a[N][N];
//int maxsum[N];//求最大和 
int *maxsum;
int main()
{
	freopen("a.txt","r",stdin);
	int n;
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j <= i; ++j)
		{
			cin >> a[i][j];
		}
	}
	/*
	for(int i = 1; i <= n; ++i)
	{
		maxsum[i] = a[n][i];
	}
	*/
	maxsum = a[n];//maxsum指向第n行 
	for(int i = n-1; i >= 1; --i)
	{
		for(int j = 1; j <= n; ++j)
		{
			maxsum[j] = max(maxsum[j],maxsum[j+1]) + a[i][j];
		}
	}
	cout << maxsum[1] << endl;
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/yanyanwenmeng/article/details/83338829