动态规划——数字三角形(递归or递推or记忆化搜索)

动态规划的核心就是状态和状态转移方程。

对于该题,需要用抽象的方法思考,把当前的位置(i,j)看成一个状态,然后定义状态的指标函数d(i,j)为从格子出发时能得到的最大和(包括格子本身的值)。

在这个状态定义下,原问题的解就是d(i,j).

下面看一下不同状态之间如何转移。从格子(i,j)出发有两种策略。如果向左走,则到(i+1,j)后需要求“从(i+1,j)出发能得到的最大和”这一问题,即d(i+1,j)。

类似的,往右走之后需要求解d(i+1,j+1).由于可以在这两个决策中自由选择,所以应选择其中较大者。换句话说就是得到状态转移方程

d(i,j)=a(i,j)+Max(d(i+1,j),d(i+1,j+1))

这样就保证了子树的最优,这个性质称为最优子结构。

用直接递归的方法计算状态转移方程,效率往往十分低下。其原因是相同的子问题被重复计算了多次。

因此我们对其优化采用了递推算法或者采用记忆搜索的方式。

递推计算就是把每个问题直接罗列出来,因此不会重复。

记忆搜索的程序依然是递归的,但是把计算结果放在了数组d中。开始将所有状态置为-1,只要是计算过的状态就就变成非负,因此只要判断是否d[i][j]>=0,就知道它是否计算过。

#include<iostream>
#include<string>
using namespace std;
void input(int a[][10],int n)
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<=i;j++)
        {
            cin>>a[i][j];
        }
    }
}
int max(int a,int b)
{
    if(a>b)
        return a;
    else
        return b;
}
/*******************i表示当前行数,j表示当前列数,n表示规格****************************/
/**********d(i,j)表示状态,d(i,j)=a(i,j)+Max(d(i+1,j),d(i+1,j+1))为状态转移方程*********/
int d(int a[][10],int i,int j,int n)
{
    if(i>=n)
        return 0;
    else
    {
        return a[i][j]+max(d(a,i+1,j,n),d(a,i+1,j+1,n));
    }
}
/**************采用递推计算,i表示当前行数,j表示当前列数,n表示规格**********************************/
int d1(int a[][10],int n)
{
    int i,j;
    int b[10][10];
    for(i=0;i<=n;i++)
        b[n][i]=0;        //将b(n,0~n)状态全部赋值为0
    for(i=n-1;i>=0;i--)
    {
        for(j=0;j<=i;j++)
        {
            b[i][j]=a[i][j]+max(b[i+1][j],b[i+1][j+1]);
        }
    }
    return b[0][0];
}

/*************采用记忆化搜索*************************/
int d2(int a[][10],int b[][10],int i,int j,int n)
{
    if(b[i][j]>=0)
        return b[i][j];
    else
    {
        if(i>=n)
            return 0;
        else
            return b[i][j]=a[i][j]+max(d2(a,b,i+1,j,n),d2(a,b,i+1,j+1,n));
    }
}
int main()
{

    int a[10][10];
    int b[10][10];
    memset(b,-1,sizeof(b));
    int n;
    cout<<"请输入总共有多少行"<<endl;
    cin>>n;
    input(a,n);
    cout<<d(a,0,0,n)<<endl;
    cout<<d1(a,n)<<endl;
    cout<<d2(a,b,0,0,n)<<endl;
    return 0;
}

时间: 2024-09-30 21:19:53

动态规划——数字三角形(递归or递推or记忆化搜索)的相关文章

数字三角形——递归、递推、记忆化搜索

数字三角形 描述: 有一个由非负整数组成的三角形,第一行只有一个数,除了最下行之外没个数的左下方和右下方各有一个数. 问题: 从第一行的数开始,每次可以往左下或右下走一格,直到走到最下行,把沿途经过的数全部加起来.如何走才能使得这个和尽量大? 分析: 不难看出此题是一个动态的决策问题:每次有两种选择--左下或右下.如果用回溯法求出所有的可能的路线,就可以从中选出最优的路线.但和往常一样,回溯法的效率太低:一个n层数字三角形的完整路线有2^n条,当n很大时回溯法的速度将让人无法忍受.因此本题讨论用

动态规划 数字三角形(递归,递推,记忆化搜索)

题目要求: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 在上面的数字三角形中寻找在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大.路径上的每一步都只能往左下或右下走.只需要求出这个最大和即可,不必给出具体路径. 三角形的行数大于1小于等于100,数字为 0 - 99 输入格式: 5 //三角形行数.下面是三角形 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 解题思路: 用二维数组存放数字三角形 D[r][j] //表示第i行第j个元素的

递归,递推,记忆化搜索,空间优化(数字三角形)

题目链接:http://poj.org/problem?id=1163 1.递归思想:第一层到最底层的最优路径可以分解为:第一层到第二层来,再加上第二层的最优路径 状态: Time Limit Exceeded #include <algorithm> #include <stdio.h> #define MAX 101 using namespace std; int maps[MAX][MAX]; int n; int Sum(int i,int j) { if(i==n) r

洛谷 P1464 Function【动态规划(递推)/记忆化搜索(递归)】

题目描述 对于一个递归函数w(a,b,c) 如果a<=0 or b<=0 or c<=0就返回值1. 如果a>20 or b>20 or c>20就返回w(20,20,20) 如果a<b并且b<c 就返回w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c) 其它别的情况就返回w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1) 这是个简单的递归函数,但实现起来可能会有些问题.当a,b,c均为1

[动态规划]数字三角形

动态规划一直是一个很头疼的问题啊. 最近在看这方面的东西,记录一下刘汝佳书里的动态规划章节里的数字三角形题目. 这道题很基础,但总结的三个动态规划很清晰. 有一个由非负整数组成的三角形,第一行只有一个数,除了最下行之外每个数的左下方和右下方各有一个数,形如: 1 3 2 4 10 1 4 3 2 20 每个结点都可到它左右子结点,例如3可以到4也可以到10. 从第一行开始每次可以往左下或右下走一格,直到走到最下,把沿途结点的值相加,如何走才能得到最大值. 如果遍历的话,n层会有2的n次方种可能性

【递归与递推】计数器

问题 F: [递归与递推]计数器 题目描述 一本书的页数为N,页码从1开始编起,请你求出全部页码中,用了多少个0,1,2,…,9.其中—个页码不含多余的0,如N=1234时第5页不是0005,只是5. 输入 一个正整数N(N≤109),表示总的页码. 输出 共十行:第k行为数字k-1的个数. 样例输入 11 样例输出 1 4 1 1 1 1 1 1 1 1 #include <iostream> #include <cstring> #include <cstdio>

【递归与递推】电话号码

问题 L: [递归与递推]电话号码 题目描述 电话机上每一个数字下面都写了若干个英文字母.分布如下:       1-abc       2-def       3-ghi       4-ikl       5-mn       6-opq       7-rst       8-uvw       9-xyz  现在给定一个单词表和一串数字密码,请你用单词表中的单词翻译这个密码. 输入 第一行为一个正整数N表示单词表中单词的个数(N≤100): 第二行为一个长度不超过100的数字串,表示密码

【递归与递推】诸侯安置

[递归与递推]诸侯安置 题目描述 很久以前,有一个强大的帝国,它的国土成正方形状,如图2—2所示. 这个国家有若干诸侯.由于这些诸侯都曾立下赫赫战功,国王准备给他们每人一块封地(正方形中的一格).但是,这些诸侯又非常好战,当两个诸侯位于同一行或同一列时,他们就会开战.如下图2—3为n=3时的国土,阴影部分表示诸侯所处的位置.前两幅图中的诸侯可以互相攻击,第三幅则不可以. 国王自然不愿意看到他的诸侯们互相开战,致使国家动荡不安.  因此,他希望通过合理的安排诸侯所处的位置,使他们两两之间都不能攻击

【递归与递推】排序集合

[递归与递推]排序集合 题目描述 对于集合N={1,2,…,n}的子集,定义一个称之为“小于”的关系:设S1={X1,X2,…,Xi},(X1<X2<…<Xi),S2={Y1, Y2, …,Yj},(Y1<Y2<…<Yj),如果存在一个k,(0≤k≤min(i,j)),使得X1=Y1,…,Xk=Yk,且k=i或X(k+1)<Y(k+1),则称S1“小于”S2.你的任务是,对于任意的n(n≤31)及k(k<2n),求出第k小的子集. 输入 仅一行,包含两个用空