1. 程式人生 > >動態規劃(入門):各種數字三角形

動態規劃(入門):各種數字三角形

一、一般的數字三角形:

        給一個由數字形成的三角形,要求從三角形的頂端開始走,走到最後一行,要求走的路徑之和最大。對於一般的數字三角行,可以正著走,也可以反著走。建議最好正走,不然加強版的數字三角形倒著走走不出來。

例題:

描述
示出了一個數字三角形。 請編一個程式計算從頂至底的某處的一條路
徑,使該路徑所經過的數字的總和最大。
  每一步可沿左斜線向下或右斜線向下走;
  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);
    }
}