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;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值