動態規劃(入門):各種數字三角形
阿新 • • 發佈:2019-02-11
一、一般的數字三角形:
給一個由數字形成的三角形,要求從三角形的頂端開始走,走到最後一行,要求走的路徑之和最大。對於一般的數字三角行,可以正著走,也可以反著走。建議最好正走,不然加強版的數字三角形倒著走走不出來。
例題:
描述
示出了一個數字三角形。 請編一個程式計算從頂至底的某處的一條路
徑,使該路徑所經過的數字的總和最大。
每一步可沿左斜線向下或右斜線向下走;
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);
}
}