Cow Bowling

The cows don't use actual bowling balls when they go bowling. They each take a number (in the range 0..99), though, and line up in a standard bowling-pin-like triangle like this: 

          7



        3   8



      8   1   0



    2   7   4   4



  4   5   2   6   5
Then the other cows traverse the triangle starting from its tip and moving "down" to one of the two diagonally adjacent cows until the "bottom" row is reached. The cow's score is the sum of the numbers of the cows visited along the way. The cow with the highest score wins that frame. 

Given a triangle with N (1 <= N <= 350) rows, determine the highest possible sum achievable.

Input

Line 1: A single integer, N 

Lines 2..N+1: Line i+1 contains i space-separated integers that represent row i of the triangle.

Output

Line 1: The largest sum achievable using the traversal rules

Sample Input

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

Sample Output

30
Hint
Explanation of the sample: 

          7

         *

        3   8

       *

      8   1   0

       *

    2   7   4   4

       *

  4   5   2   6   5
The highest score is achievable by traversing the cows as shown above.

题型:动态规划数字三角形类型

题解:从第一行的数开始,每次可以往左下或右下走一格,直到走到最下行,把沿途经过的数全部加起来。如何走才能使得这个和尽量大?

析:

若采用回溯法,效率太低。需抽象的方法思考问题:把当前位置(i,j)看成一个状态,然后定义状态(i,j)的指标函数d(i,j)为从格子(i,j)出发时能得到的最大和(包括格子(i,j)本身的值)。在这个定义状态下,原问题的解为d(1,1)。从格子(i,j)出发有两种决策,往左走d(i+1,j),往右走d(i+1,j+1),选择其中较大的一个得到了状态转移方程:

    d(i,j)=str(i,j)+max{d(i+1,j),d(i+1,j+1)}

法一:用递归计算由于重复计算导致时间效率太低

法二:可用递推计算,但须注意边界处理的问题,时间复杂度为O(n^2)

i逆序枚举,在计算的d[i][j]之前他所需要的d[i+1][j]和d[i+1][j+1]已经计算出来了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int d[1010][1010];
int str[1010][1010];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin>>str[i][j];
		}
	}
	memset(d,0,sizeof(d));
	for(int i=n;i>=1;i--){
		for(int j=1;j<=i;j++){
			d[i][j]=max(d[i+1][j],d[i+1][j+1])+str[i][j];
		}
	}
	cout<<d[1][1]<<endl;
}

法三

记忆化搜索,编写递归函数,同时将计算结果保存在数组d中,通过判断是否d[i][j]>=0得知它是否已经被计算过。

#include<iostream>
#include<string.h>
using namespace std;
int d[1001][1001];
int str[1001][1001];
int n;
int solve(int i,int j)
{
    if(d[i][j]>=0)
        return d[i][j];
    return d[i][j]=str[i][j]+(i==n?0:max(solve(i+1,j),solve(i+1,j+1)));
}
int main()
{
    int i,j;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=i;j++)
        {
            cin>>str[i][j];
        }
    }
    //记忆化搜索的方法。首先初始化d,然后编写递归函数
    memset(d,-1,sizeof(d));
    solve(1,1);
    cout<<d[1][1]<<endl;
}

猜你喜欢

转载自blog.csdn.net/lshsgbb2333/article/details/79842751