POJ2760:数字三角形

总时间限制: 
1000ms
内存限制: 
65536kB
描述
7
3   8
8   1   0
2   7   4   4
4   5   2   6   5

(图1)

图1给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。

注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的那个数或者右边的那个数。
输入
输入的是一行是一个整数N (1 < N <= 100),给出三角形的行数。下面的N行给出数字三角形。数字三角形上的数的范围都在0和100之间。
输出
输出最大的和。
样例输入
5
7
3 8
8 1 0 
2 7 4 4
4 5 2 6 5

样例输出

30




思路1:

(1,1)

(2,1)(2,2)

(3,1)(3,2)(3,3)

    1、递推

   (1,1) -> Max[(2,1),(2,2)]               (1,1)往下找最大的数求和

    (2,1)    ->Max[(3,1),(3,2)]             

    (2,2)   ->Max[(3,2),(3,3)]                

    (r,c)->Max [(r+1,c),(r+1,c+1)]        (r,c)往下找最大的数求和

    nSum1 nSum2 分别保存(r+1,c),(r+1,c+1)的数

    2、判别大小,求和

          若nSum1大,则 f(r,c)=nSum1+(r,c);    否则f(r,c)=nSum2+(r,c);

   3、(1,1) 往下递归,直到第n层,即返回r=n时的(r,c)的值 。



#include<iostream>
using namespace std;
#define MAX 100 
int arr[MAX+10][MAX-10];
int num;

int MaxSum(int r,int j){
	if(r==num)
		return arr[r][j];
	int nSum1=MaxSum(r+1,j);
	int nSum2=MaxSum(r+1,j+1);
	if(nSum1>nSum2)
	{
		return nSum1+arr[r][j];
	}
	return nSum2+arr[r][j];
}

int  main()
{
    int x;
    while(cin>>num)
    {    
    	for(int i=1;i<=num;i++)
        	for(int j=1;j<=i;j++)
				cin>>arr[i][j];
		cout<<MaxSum(1,1)<<endl;	
    }
    return 0;
}

状态: Time Limit Exceeded

递归,OJ判定会超时。

不难总结规律,对于N行的三角形,总的计算次数是

2^0 + 2^1  + 2^2 + 2^3 + …… + 2^(N-1) = 2^N。

当N=100时,总的计算次数是一个很大的数字。  

2^100=1,267,650,600,228,229,401,496,703,205,376    结果是31位的数。

      


思路2:

    在思路1的基础上,将中间结果保存以避免重复计算。-》动态规划

#include<iostream>
using namespace std;
#include<memory.h>
#define MAX 100 
int arr[MAX+10][MAX-10];
int num;
int aMaxSum[MAX+10][MAX+10];

int  func(int r,int c){
	if(r==num)
		return arr[r][c];
	if(aMaxSum[r+1][c]==-1)
		//如果MaxSum(r+1,c)没计算过 
		aMaxSum[r+1][c]=func(r+1,c);
	if(aMaxSum[r+1][c+1]==-1)
		//如果MaxSum(r+1,c+1)没有计算过 
		aMaxSum[r+1][c+1]=func(r+1,c+1);
	if(aMaxSum[r+1][c]>aMaxSum[r+1][c+1])
		return aMaxSum[r+1][c]+arr[r][c];
	return aMaxSum[r+1][c+1] + arr[r][c];
}

int  main()
{
    int x;
    // 将aMaxSum全部置-1,表示开始所有的MaxSum(r,c)都没计算过 
    memset(aMaxSum,-1,sizeof(aMaxSum));
    while(cin>>num)
    {    
    	for(int i=1;i<=num;i++)
        	for(int j=1;j<=i;j++)
				cin>>arr[i][j];
		cout<<func(1,1)<<endl;	
    }
    return 0;
}

思路3:

      不用递归函数实现递归思想。从aMaxSum[N-1]这一行元素开始向上逐行递推得到aMaxSum[1][1],实现这一逆过程。


#include<iostream>
using namespace std;
#include<memory.h>
#define MAX 100 
int arr[MAX+10][MAX-10];
int num;
int aMaxSum[MAX+10][MAX+10];

void prepare(){
	for(int i=1;i<=num;i++)
	{
		aMaxSum[num][i]=arr[num][i];
	}
	for(int i=num;i>1;i--)
	{
		for(int j=1;j<i;j++)
		{
			if(aMaxSum[i][j]>aMaxSum[i][j+1])
				aMaxSum[i-1][j]=aMaxSum[i][j]+arr[i-1][j];
			else
				aMaxSum[i-1][j]=aMaxSum[i][j+1]+arr[i-1][j]; 
		}
	}
}

int  main()
{
    int x;
    while(cin>>num)
    {   
	    memset(aMaxSum,-1,sizeof(aMaxSum)); 
    	for(int i=1;i<=num;i++)
        	for(int j=1;j<=i;j++)
				cin>>arr[i][j];	
		prepare();
		cout<<aMaxSum[1][1]<<endl;	
    }
    return 0;
}









猜你喜欢

转载自blog.csdn.net/beautifulxu/article/details/80650944
今日推荐