2020.7.27考試D1T1:Cow Pie Treasures
原題目:
知乎回答:DP水題賽爆零是一種怎樣的體驗?
D1T1:Cow Pie Treasures
Description
最近,奶牛們熱衷於把金幣包在麵粉裡,然後把它們烤成餡餅。第i塊餡餅中含有Ni(1<=Ni<=25)塊金幣,並且,這個數字被醒目地標記在餡餅表面。 奶牛們把所有烤好的餡餅在草地上排成了一個R行(1<=R<=100)C列(1<=C<=100)的矩陣。你現在站在座標為(1,1)的餡餅邊上,當然,你可以拿到那塊餡餅裡的所有金幣。你必須從現在的位置,走到草地的另一邊,在座標為(R,C)的餡餅旁邊停止走動。每做一次移動,你必須走到下一列的某塊餡餅旁邊,並且,行數的變動不能超過1(也就是說,如果現在你站在座標為(r,c)的餡餅邊上,下一步你可以走到座標為(r-1,c+1),(r,c+1),或者(r+1,c+1)的餡餅旁邊)。當你從一塊餡餅邊經過,你就可以拿走餡餅裡所有的金幣。當然啦,你一定不會願意因半路離開草地而失去唾手可得的金幣,但,最終你一定得停在座標為(R,C)的餡餅旁邊。 現在,你拿到了一張標記著餡餅矩陣中,每一塊餡餅含金幣數量的表格。那麼,按照規則,你最多可以拿到多少金幣呢? 比方說,奶牛們把餡餅排成如下的矩陣,矩陣中的數字表示該位置的餡餅中含金幣的數量:
6 5 3 7 9 2 7
2 4 3 5 6 8 6
4 9 9 9 1 5 8
以下是條合法的路線
按上述的路線進行走動,一共可以獲得6+4+9+9+6+5+8=47個金幣.按照規則,在這個矩陣中最多可以得到50個金幣,路線如下圖所示:
Input
第1行: 兩個用空格隔開的整數,R和C
第2..R+1行: 每行包含C個用空格隔開的正整數,依次表示一行中從左往右各個餡餅裡金幣的數量
Output
輸出一個正整數,表示你所能收集到的最大金幣數目
Sample Input
3 7
6 5 3 7 9 2 7
2 4 3 5 6 8 6
4 9 9 9 1 5 8
Sample Output
50
思路
看起來是道移動類DP水題,實際上有個坑
先來看思路:
題目告訴我們了可以怎麼走
下一步你可以走到座標為(r-1,c+1),(r,c+1),或者(r+1,c+1)的餡餅旁邊
所以直接得到動態轉移方程
dp[j][i]=max(dp[j-1][i-1],max(dp[j+1][i-1],dp[j][i-1]))+a[j][i];
所以再逐列推導
for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ dp[j][i]=max(dp[j-1][i-1],max(dp[j+1][i-1],dp[j][i-1]))+a[j][i]; } }
因為只能向右、右下、右上走
所以起點到終點連成的對角線以下部分是到達不了的(這是一個坑)
就增加判斷
if(j<=i){
}
程式碼
所以程式碼就出來了
#include<bits/stdc++.h> using namespace std; int n,m; int a[1010][1010]; int dp[1010][1010]; bool in(int x,int y){ return x>=1&&y<=x&&x<=n&&y<=m; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>a[i][j]; } } dp[1][1]=a[1][1]; //DFS(1,1); for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ if(j<=i){ dp[j][i]=max(dp[j-1][i-1],max(dp[j+1][i-1],dp[j][i-1]))+a[j][i]; } } } cout<<dp[n][m]; return 0; }