动态规划(入门):各种数字三角形

来源:互联网 发布:临时身份证制作软件 编辑:程序博客网 时间:2024/06/16 07:58

一、一般的数字三角形:

        给一个由数字形成的三角形,要求从三角形的顶端开始走,走到最后一行,要求走的路径之和最大。对于一般的数字三角行,可以正着走,也可以反着走。建议最好正走,不然加强版的数字三角形倒着走走不出来。


例题:

描述
示出了一个数字三角形。 请编一个程序计算从顶至底的某处的一条路
径,使该路径所经过的数字的总和最大。
  每一步可沿左斜线向下或右斜线向下走;
  1<三角形行数<25;
  三角形中的数字为整数<1000;

输入格式
第一行为N,表示有N行
后面N行表示三角形每条路的路径权
输出格式
路径所经过的数字的总和最大的答案
测试样例1
输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出
30


正走代码:

#include<bits/stdc++.h>using namespace std;const int maxn = 25+5;int maps[maxn][maxn];int main(){    int n;    while(~scanf("%d",&n))    {        memset(maps,0,sizeof(maps));        for(int i=1;i<=n;i++)//从1开始并且初始化为0可以直接从(1,1)开始走            for(int j=1;j<=i;j++)                {                    int now;                    scanf("%d",&now);                    maps[i][j] = max(maps[i-1][j],maps[i-1][j-1]) + now;                }        int ans = 0;        for(int i=1;i<=n;i++)            ans = max(maps[n][i],ans);//正走在最后需要找出各个路径走到最后一行时最大的一个数;        printf("%d\n",ans);    }}

反走代码:

#include<bits/stdc++.h>using namespace std;const int maxn = 25+5;int maps[maxn][maxn];int main(){    int n;    while(~scanf("%d",&n))    {        memset(maps,0,sizeof(maps));        for(int i=1;i<=n;i++)            for(int j=1;j<=i;j++)                scanf("%d",&maps[i][j]);        for(int i=n-1;i>=0;i--)            for(int j=1;j<=i;j++)                maps[i][j] += max(maps[i+1][j],maps[i+1][j+1]);        printf("%d\n",maps[1][1]);//反走的优势就在于此处,最大值直接就在(1,1)产生    }}


二、过定点的数字三角形(加强版一)
        还是数字三角形,多了一个要求,就是需要走固定的一个点。这个题的想法很有意思,化一般为特殊,具体的做法就是将固定的点加上一个很大的数,在规划的过程中就一定会走过这个点,在输出的时候将这个很大的数减去就是正确答案。但是在加上一个很大的数的时候需要计算一下,不要加上一个很大的数的时候超范围了就很尴尬了。

例题:
描述
数字三角形必须经过某一个点,使之走的路程和最大
输入格式
第1行n,表示n行 <=25
第2到n+1行为每个的权值
第n+2行为两个数x,y表示必须经过的点
输出格式
最大值
测试样例1
输入
2
1
1 1
1 1
输出
2

#include<bits/stdc++.h>using namespace std;const int maxn = 25 + 5;const int Max = 1e5;int maps[maxn][maxn];int main(){    int n;    while(~scanf("%d",&n))    {        memset(maps,0,sizeof(maps));        for(int i=1;i<=n;i++)            for(int j=1;j<=i;j++)                scanf("%d",&maps[i][j]);        int x,y;        scanf("%d%d",&x,&y);        maps[x][y] += Max;//加上最大就一定会走过此点        for(int i=1;i<=n;i++)            for(int j=1;j<=i;j++)                maps[i][j] += max(maps[i-1][j],maps[i-1][j-1]);        int ans = 0;        for(int i=1;i<=n;i++)            ans = max(ans,maps[n][i]);        printf("%d\n",ans - Max);//最后输出的时候不要忘记减去Max    }}

三、数字三角形mod100(加强版二)
        这个题很能体现动态规划的思想,记录的主要是状态,下一个状态由前一个状态得到。
        首先开一个三维数组,三位数组的前两维用来记录行和列,第三维大小开100,即0~99.用来记录状态(思考为什么是0~99)(其实第三维就是用来记录这个位置可能得到的所有的答案),看是否有这个数字,当这个数字存在的时候将第三维,也就是的这个数字记录的true(其实就是记录每次%100所得到的答案),下一个行就在上一行true的情况下转移。第【0】【0】【0】,【0】【1】【0】记录为true。这个题是将所有可能的得到的答案全部记录下来,最后遍历看最大的值。(嘴笨说不清楚

例题:
描述
数字三角形
要求走到最后mod 100最大
输入格式
第1行n,表示n行 <=25
第2到n+1行为每个的权值
输出格式
mod 100最大值
测试样例1
输入
2
1
99 98
输出
99



#include<bits/stdc++.h>using namespace std;const int Mod = 100;const int maxn = 25 + 5;int maps[maxn][maxn];bool dp[maxn][maxn][100];int main(){    int n;    while(~scanf("%d",&n))    {        memset(maps,0,sizeof(maps));        memset(dp,0,sizeof(dp));        for(int i=1;i<=n;i++)            for(int j=1;j<=i;j++)                scanf("%d",&maps[i][j]);        dp[0][0][0] = dp[0][1][0] = true;//这个初始化很重要        for(int i=1;i<=n;i++)            for(int j=1;j<=i;j++)            {                for(int k=0;k<=99;k++)                {                    int now;                    if(dp[i-1][j][k])//当上一个这个数值存在时就可以加上当前状态的值                    {                        now = (maps[i][j] + k)%Mod;                        dp[i][j][now] = true;                    }                    if(dp[i-1][j-1][k])                    {                        now = (maps[i][j] + k)%Mod;                        dp[i][j][now] = true;                    }                }            }        int ans = 0;        for(int i=1;i<=n;i++)            for(int k=0;k<=99;k++)            {                if(dp[n][i][k])                {                    ans = max(ans,k);                }            }        printf("%d\n",ans);    }}



原创粉丝点击