1. 程式人生 > >HDU 4826 (分類DP)

HDU 4826 (分類DP)

using 狀態 ear 單獨 space names c++ bit 初始化

Labyrinth

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1368 Accepted Submission(s): 574


Problem Description 度度熊是一只喜歡探險的熊,一次偶然落進了一個m*n矩陣的迷宮,該迷宮只能從矩陣左上角第一個方格開始走,只有走到右上角的第一個格子才算走出迷宮,每一次只能走一格,且只能向上向下向右走以前沒有走過的格子,每一個格子中都有一些金幣(或正或負,有可能遇到強盜攔路搶劫,度度熊身上金幣可以為負,需要給強盜寫欠條
),度度熊剛開始時身上金幣數為0,問度度熊走出迷宮時候身上最多有多少金幣?

Input 輸入的第一行是一個整數T(T < 200),表示共有T組數據。
每組數據的第一行輸入兩個正整數m,n(m<=100,n<=100)。接下來的m行,每行n個整數,分別代表相應格子中能得到金幣的數量,每個整數都大於等於-100且小於等於100。

Output 對於每組數據,首先需要輸出單獨一行”Case #?:”,其中問號處應填入當前的數據組數,組數從1開始計算。
每組測試數據輸出一行,輸出一個整數,代表根據最優的打法,你走到右上角時可以獲得的最大金幣數目。

Sample Input 2 3 4 1 -1 1 0 2 -2 4 2 3 5 1 -90 2 2 1 1 1 1

Sample Output Case #1: 18 Case #2: 4

Source 2014年百度之星程序設計大賽 - 資格賽 一開始想記憶化搜索,結果越寫越亂,直接爆搜肯定TLE. DP的話,不像以前的題目只能向下和向右,多了一個向上的方向,如果還是一行一行遞推的話,顯然有些狀態會被遺漏,這不是正確做法。 我們設想,假如在某一點,要想知道其最大值,有三種情況:從上方過來,從下方過來,從左面過來. 可是對於上下這種狀態,兩個要同時知道才能知道最優解,顯然無法直接遞推出來。 我們不妨根據上下分類討論dp[i][j][k]表示(i,j)點根據方式k得到的最優解,k有兩種,up-->down||down-->up; 由於會出現負數,所以註意邊界數據的初始化。(我被這個坑了WA幾次)

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int N,M,e[105][105],dp[105][105][2];
int solve()
{
int i,j,k;
memset(dp,-inf,sizeof(dp)); dp[0][1][0]=0;
for(i=1;i<=N;++i) dp[i][1][0]=dp[i-1][1][0]+e[i][1];
for(i=2;i<=M;++i)
{
for(j=N;j>=1;j--) dp[j][i][1]=max(dp[j+1][i][1],max(dp[j][i-1][0],dp[j][i-1][1]))+e[j][i];
for(j=1;j<=N;j++) dp[j][i][0]=max(dp[j-1][i][0],max(dp[j][i-1][0],dp[j][i-1][1]))+e[j][i];
}
return max(dp[1][M][0],dp[1][M][1]);
}
int main()
{
int t,i,j,k;
cin>>t;
for(int tes=1;tes<=t;++tes){
cin>>N>>M;
for(i=1;i<=N;++i)
for(j=1;j<=M;++j) scanf("%d",&e[i][j]);
printf("Case #%d:\n%d\n",tes,solve());
}
return 0;
}

HDU 4826 (分類DP)