poj 1163 The Triangle (动态规划入门题)

The Triangle
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 33836 Accepted: 20105

Description

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

(Figure 1)
Figure 1 shows a number triangle. Write a program that calculates the highest sum of numbers passed on a route that starts at the top and ends somewhere on the base. Each step can go either diagonally down to the left or diagonally down to the right.

Input

Your program is to read from standard input. The first line contains one integer N: the number of rows in the triangle. The following N lines describe the data of the triangle. The number of rows in the triangle is > 1 but <= 100. The numbers in the triangle, all integers, are between 0 and 99.

Output

Your program is to write to standard output. The highest sum is written as an integer.

Sample Input

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

Sample Output

30

Source


题意:
有一个n层的三角形,第i层有i个数。至顶向下走每次都可以从i-1行j列走到i行j列,或者i行j+1列。问到达
底层时经过路径的最大权值和。

分析:
这题开始把动规方程写成了dp[i][j]=dp[i][j]+max(a[i][j],a[i][j+1])。很明显的错误。并不是像贪心一样每次都是选
的一行中可走步数的最优解。因为这次最优,到下次加了一个值以后不一定最优,就不能保证最后找到的是
最优解。

既然这样,是不是只能把所有的路径得到的值全记录下来,然后到最后一行再比较大小呢?
或者说用dp[i][j]=max(dp[i][j],dp[i-1][j]+a[i][j])   和  dp[i][j]=max(dp[i-1][j]+a[i][j+1],dp[i][j]) 一起判断呢?

如果换一个思路。从底向上搜,多个点逐渐缩为一个点。保证了最优子结构和无后效性。
dp方程:dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j]
               (dp[i][j]表示以i行j列为终点的权值和。)

想到这里,其实从上往下搜其实也是可以的。
从上一层状态到下一层状态,每次只考虑单独地考虑当前状态是由上一层的哪几个状态得到,而不能考虑
当前的两个状态是由上一层状态的某个状态得到。上推下和下推上都要遵循是当前状态为1,且保证此时
1对1 或者1对多。

dp方程:dp[i][j]+=max(dp[i-1][j-1],dp[i-1][j])
              (dp[i][j]表示以i行j列为终点的权值和。)
这里就省去了a[][]数组的记录。
dp方程怎么来的?  每次i行j列的点都可以由i-1行j列的点和i-1行j-1列的点得到。
但是从底往上搜快。

AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int a[105][105];
int dp[105][105];

int main()
{
    int r,i,j;
    memset(dp,0,sizeof(dp));
    scanf("%d",&r);
    for(i=1;i<=r;i++)
    {
        for(j=1;j<=i;j++)
            scanf("%d",&a[i][j]);
    }
    for(i=1;i<=r;i++)
        dp[r][i]=a[r][i];
    for(i=r-1;i>=1;i--)
    {
        for(j=1;j<=i;j++)
        {
            dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];
            //printf("test: %d\n",dp[i][j]);
        }
    }
    printf("%d\n",dp[1][1]);
    return 0;
}

//0MS
//从下往上搜


11996488

fukan

1163

Accepted

252K

0MS

C++

614B

2013-08-17 09:55:47


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int dp[105][105];

int main()
{
    int r,i,j;
    memset(dp,0,sizeof(dp));
    scanf("%d",&r);
    for(i=1;i<=r;i++)
    {
        for(j=1;j<=i;j++)
            scanf("%d",&dp[i][j]);
    }
    for(i=2;i<=r;i++)
    {
        for(j=1;j<=i;j++)
        {
            dp[i][j]+=max(dp[i-1][j-1],dp[i-1][j]);
            //printf("test: %d\n",dp[i][j]);
        }
    }
    int ans=0;
    for(i=1;i<=r;i++)
        ans=max(dp[r][i],ans);
    printf("%d\n",ans);
    return 0;
}

//从上往下搜
//32MS

11997417

fukan

1163

Accepted

208K

32MS

C++

604B

2013-08-17 12:57:52


               


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值