POJ--3176 Cow Bowling(DP)

记录
23:51 2023-5-14

http://poj.org/problem?id=3176

reference:《挑战程序设计竞赛(第2版)》第二章练习题索引 p135

Description

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

简单的动态规划问题(hhh,保持乐观)

先按记忆中的想法总结以下动态规划步骤(哈哈哈,还没做几道题就要总结,真是纯纯的joker)
(ps:再吐槽一下算法老师,当时讲的太抽象了,对我这种学生抽象知识得慢慢学,当时上算法课是2020夏天,在家的一个学期,老师讲的我理解不能,差点emo了)
(pps:不是说老师讲的抽象不好,这种抽象给已经有过算法经理的同学还是比较好,对我来说应该需要instructive的内容才好(我又在放洋屁了))

  1. 定义dp数组种某个元素的定义(注意边界条件,合理的dp数组的定义是设计递推公式的前提) 状态
  2. 定义递推公式(重中之重,有趣的想法和记忆化搜索全部体现在这个中) 状态转移方程
  3. 遍历计算结果

anything else?
dp数组的重复利用(system方向的程序员就是要拿最小的内存干最大的事
这道题 dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + tri[i][j] (i j 都从1开始比较好,我code里从0开始的不好,在这个上下文中假设i j 都从1开始)
那么dp[j] 计算只需要dp[j-1]和dp[j]
如果是dp[i][j] = max(dp[i-1][j], dp[i-1][j + 1]) + tri[i][j] (假设,为了更好的理解)
那么dp[j] 计算只需要dp[j]和dp[j+1],这种情况下按正常顺序读入,按照dp[j] = max(dp[j] + dp[j+1]) + a(读入的值) 这成立的情况正是由于dp[j]只需要当前dp[j]和dp[j+1] (更新到dp[j]不会影响到dp[j+1] (这是下一个元素需要使用的))
但是对于dp[j] = max(dp[j] + dp[j-1]) + a(读入的值) 如果正常顺序读入,dp[j]被更新,下一个读入的值对应的dp[j-1]是这个dp[j],这样子就冲突了。
解决的方法是读入的元素从右边没有元素的那个开始计算(这个说法有点抽象,最下面写了代码,一起看更好理解) (j+1 和 j-1 导致了更新的方向)

有意思的地方:
这道题POJ的discuss中有人问为什么每道题都和牛牛有关,hhhhh。

((__))________?
 (00) (_)     |
 (oo)\___(_)__/
      |  | vvv|
ref: http://poj.org/showmessage?message_id=156995 @DE_SEAN

本道题的收获

  1. 做dp的信心?
  2. c++中max_element函数(擦,我居然不知道这个函数,加油学噢)
  3. 简化dp(dp数组的重复利用)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAX_N 350
typedef long long ll;
typedef unsigned int uint;
const int INF = 0x3f3f3f3f;

int tri[MAX_N + 1][MAX_N + 1]; // j <= i
int dp[MAX_N + 1][MAX_N + 1];  //定义dp[i][j] = 到这个点的时候得到的最大的值
int N;
// dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + tri[i][j] (if dp[i-1][j-1] exists else dp[i-1][j] + tri[i][j])

void solve() {
    dp[0][0] = tri[0][0];
    for(int i = 1; i < N; i++) {
        for(int j = 0; j <= i; j++) {
            if(j >= 1) {
                dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + tri[i][j];
            } else {
                dp[i][j] = dp[i-1][j] + tri[i][j];
            }
        }
    }
    int result = -INF;
    for(int i = 0; i < N; i++) {
        if(dp[N-1][i] > result) {
            result = dp[N-1][i];
        }
    }
    printf("%d\n", result);
}

int main() {
    scanf("%d", &N);
    for(int i = 0; i < N; i++) {
        for(int j = 0; j <= i; j++) {
            scanf("%d", &tri[i][j]);
        }
    }
    solve(); 
}
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define MAX_N 350
typedef long long ll;
typedef unsigned int uint;
const int INF = 0x3f3f3f3f;

int dp[MAX_N + 1];  //定义dp[i] = 到这个点的时候得到的最大的值
int N;
// dp[i] = max(dp[i-1], dp[i]) + a; a表示此时读入的值

int main() {
    scanf("%d", &N);
    int a = 0;
    int result = -INF;
    for(int i = 1; i <= N; i++) {
        for(int j = i; j >= 1; j--) {
            scanf("%d", &a);
            dp[j] = max(dp[j-1], dp[j]) + a;
            result = max(result, dp[j]);
        }
    }
    printf("%d\n", result);
}
posted @ 2023-05-14 23:52  57one  阅读(22)  评论(0)    收藏  举报