【动态规划基础】数字金字塔

题目链接:1258:【例9.2】数字金字塔

1258:【例9.2】数字金字塔

时间限制: 1000 ms         内存限制: 65536 KB
提交数: 9635     通过数: 5467

【题目描述】

观察下面的数字金字塔。写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以从当前点走到左下方的点也可以到达右下方的点。

在上面的样例中,从13到8到26到15到24的路径产生了最大的和86。

【输入】

第一个行包含R(1≤ R≤1000),表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

所有的被供应的整数是非负的且不大于100。

【输出】

单独的一行,包含那个可能得到的最大的和。

【输入样例】

5
13
11 8
12 7  26
6  14 15 8
12 7  13 24 11

【输出样例】

86

提交 统计信息 提交记录

  

 【动态规划基础】数字金字塔

  经典的动态规划水题

方法一:贪心

  题目里说了,从上往下走,要求出路径的最大值,那么我最先想到的方法就是——

  你每次都走最大的一边就可以了啊。

  就像这样:

  

  但是,如果你是一个善于造数据来验证你的算法的人,你很快就会发现自己算法的问题,就像这样:

1
2 1
1 2 9
1 2 8 9
3 3 2 9 9

  在这一组数据中,如果使用贪心算法,就会一开始就左边,从而错失下面全是9的右边。

  也就是说,贪心算法看得太近了,没有顾全大局。

方法二:搜索 & 记忆化搜索

  像我这样的暴力型选手,碰见什么题都要用搜索写一遍。可以对拍不说,写不出来的时候,还可以骗分。

#include <bits/stdc++.h>
using namespace std;

int jzt[1005][1005], maxn, summ, n;

void dfs(int i, int j){
    if(i==n){
        maxn=maxn>summ?maxn:summ;
    }
    else{
        summ+=jzt[i+1][j];
        dfs(i+1, j);
        summ-=jzt[i+1][j];
        summ+=jzt[i+1][j+1];
        dfs(i+1, j+1);
        summ-=jzt[i+1][j+1];
    }
}

int main(){
    scanf("%d", &n);
    for(int i=0; i<n; i++){
        for(int j=0; j<=i; j++){
            scanf("%d", &jzt[i][j]);
        }
    }

    dfs(0, 0);
    printf("%d", maxn+jzt[0][0]);

    return 0;
}

   T了。。

  但是没关系,我们还有搜索优化利器:记忆化。

  

  通过观察与推理,我们会发现,中间的这些点到底端的最优解会被重复计算,所以我们要把这些状态记忆下来,四舍五入约等于全部记下来(其实是我懒得做特判)。。

#include <bits/stdc++.h>
using namespace std;

int n, bz[1005][1005], jzt[1005][1005];

int dfs(int x, int y){
    if(x==n-1) return jzt[x][y];
    else{
        if(bz[x][y]) return jzt[x][y];
        else{
            bz[x][y]=1;
            jzt[x][y]+=max(dfs(x+1, y), dfs(x+1, y+1));
            return jzt[x][y];
        }
    }
}

int main(){
    scanf("%d", &n);
    for(int i=0; i<n; i++){
        for(int j=0; j<=i; j++){
            scanf("%d", &jzt[i][j]);
        }
    }
    printf("%d", dfs(0, 0));

    return 0;
}

  这次,就成功地AC了,不得不感叹记忆化的强大。其实记忆化搜索的用时就已经相当于动态规划了(这也是为什么我把搜索学好后才学动态规划)。。

方法三:动态规划(递推)

  现在,想象一下,通过某些神奇的算法,你已经成功走到了倒数第二行的某一个位置,那么下一步应该怎么走呢?

  很明显,只要走最大的那个就可以了。因为这里只有最后一步了,局部最优解就等于全局最优解。

  但事实是,你并不知道这个神奇的算法。。。所以你还是不知道你会走到倒数第二行的哪个位置。

  但是,无论如何,你最终都会走到倒数第二行的n-1个点之一。那么我们就把到任意一个点的全局最优解求出来吧。

  那么知道了倒数第二行怎么走,那么我们就再进一步吧。

通过某些神奇的算法,你已经成功走到了 n-2 行(倒数第三行)的某一个位置,那么下一步应该怎么走呢?

  这时,我们就不能通过单纯的比大小来决定了。

  但是,我们通过上一步的计算,已经知道了走到 n-1 行的最优解,而且,我们也可以算出来走到 n-1 行某一个位置之后走到的点的和(这里指之前算出的最优解)

  那么问题就很简单了,只需要走这个值最大的一边就可以了。

  

  重复这个过程。。。

  最后:

通过某些神奇的算法,你已经成功走到了第 1 行的某一个位置,那么下一步应该怎么走呢?

  显然,我们已经知道了下一步该怎么走,,而且这时,我们就可以考虑这个“神奇的算法”了。

  由于第一行只有一个数,所以我们可以肯定的是,我们走到的一定是这个位置。

  最后,再算出第一步该怎么走时,你就算出了这个最优路径。

代码:

#include <bits/stdc++.h>
using namespace std;

int n, a[1005][1005];

int main(){
    cin >> n;
    for(int i=0; i<n; i++){
        for(int j=0; j<=i; j++){
            cin >> a[i][j];
        }
    }
    for(int i=n-2; i>=0; i--){
        for(int j=0; j<=i; j++){
            a[i][j] += max(a[i+1][j], a[i+1][j+1]);
        }
    }
    cout << a[0][0];

    return 0;
}

原文地址:https://www.cnblogs.com/dong628/p/11616193.html

时间: 2024-11-09 04:53:23

【动态规划基础】数字金字塔的相关文章

1.5.1 Number Triangles 数字金字塔

★1.5.1 Number Triangles 数字金字塔 一.题目描述 考虑在下面被显示的数字金字塔. 写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大. 每一步可以走到左下方的点也可以到达右下方的点. 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 在上面的样例中,从7 到 3 到 8 到 7 到 5 的路径产生了最大和:30 PROGRAM NAME: numtri 18 INPUT FORMAT 第一个行包含 R(1<= R<=1000) ,表示行的数目

nyist oj 36 最长公共子序列 (动态规划基础题)

最长公共子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列. tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 输入 第一行给出一个整数N(0<N<100)表示待测数据组数 接

【动态规划】数字分组I

[动态规划]数字分组I 时间限制: 1 Sec  内存限制: 64 MB提交: 10  解决: 6[提交][状态][讨论版] 题目描述 给出一堆魔法石的重量,问如何分成两堆,使得它们质量和之差最小,求出这个最小值. 输入 第一行一个数n (n ≤30). 接下来n行,每行一个正整数.(每个数≤100000) 输出 一个整数表示两组数字和的最小差. 样例输入 5 1 2 3 4 5 样例输出 1 将问题转化为求背包容量为所有数总和一半的背包问题 #include <iostream> #incl

1625 数字金字塔

1625 数字金字塔 链接:http://codevs.cn/problem/1625/ USACO 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description 考虑在下面被显示的数字金字塔. 写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大. 每一步可以走到下方的点也可以到达右下方的点. 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 在上面的样例中,从 7 到 3 到 8 到 7 到 5 的路径产生了最大和:30 输入描述 Input

LA 2038 战略游戏(树的动态规划基础题/无根树转有根树/树的最大最小结点集)

题目大意就是求树的最小结点集,树上的动态规划基础题,一次深搜就可以解决问题 代码如下: #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #i

数字金字塔最大路径和——递归

题目描述 假设有如下所示的一个数字金字塔,现在,要求写一个程序来查找从顶点到底部任意处结束的路径,使路径经过的数字的和最大,并输出该路径的最大和.比如以下金字塔的和最大路径的和为7+3+8+7+5=30.7 3 2 8 1 0 2 7 4 4 4 5 2 6 5 C++ Code 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152   #include <i

nyist oj 79 拦截导弹 (动态规划基础题)

拦截导弹 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于等于前一发的高度.某天,雷达捕捉到敌国导弹来袭.由于该系统还在试用阶段,所以只用一套系统,因此有可能不能拦截所有的导弹. 输入 第一行输入测试数据组数N(1<=N<=10) 接下来一行输入这组测试数据共有多少个导弹m(1<=m<=20) 接下来行输

Python输出数字金字塔

使用Python输出一个数字金字塔 运行结果: 源代码: ''' Python输出数字金字塔 ''' for x in range(1,10): print(' '*(15-x),end='') n=x while n>=1: print(n,sep='',end='') n-=1 n+=2 while n<=x: print(n,sep='',end='') n+=1 print() 原文地址:https://www.cnblogs.com/yijiahao/p/11740372.html

shell脚本编程设计——根据输入的数输出菱形、三角形或者数字金字塔(带闪烁颜色)

shell脚本编程设计--根据输入的数输出菱形.三角形或者数字金字塔(带闪烁颜色) shell脚本程序和解释如下 #!/bin/bash #创建死循环,当输入出错或者输入"quit"字符串退出脚本程序 while true do #等待用户输入 read -p "请输入一个不大于20的正整数(输入"quit"则退出):" n #先判断字符串是否是quit if [ "$n" == "quit" ] then