1. 程式人生 > >二維動態規劃(收集蘋果)

二維動態規劃(收集蘋果)

平面上有N*M個格子,每個格子中放著一定數量的蘋果。你從左上角的格子開始,每一步只能向下走或是向右走,每次走到一個格子上就把格子裡的蘋果收集起來,這樣下去,你最多能收集到多少個蘋果
解這個問題與解其它的DP問題幾乎沒有什麼兩樣。第一步找到問題的“狀態”,第二步找到“狀態轉移方程”,然後基本上問題就解決了。首先,要找到這個問題中的“狀態”是什麼?必須注意到的一點是,到達一個格子的方式最多隻有兩種:從左邊來的(除了第一列)和從上邊來的(除了第一行)。因此為了求出到達當前格子後最多能收集到多少個蘋果,就要先去考察那些能到達當前這個格子的格子,到達它們最多能收集到多少個蘋果。 (是不是有點繞,但這句話的本質其實是DP的關鍵:欲求問題的解,先要去求子問題的解)
經過上面的分析,可以得出問題的狀態和狀態轉移方程。狀態S[i][j]表示走到(i, j)這個格子時,最多能收集到多少個蘋果。那麼,狀態轉移方程如下:
S[i][j]=A[i][j] + max(S[i-1][j] if i>0 ; S[i][j-1], if j>0)


其中i代表行,j代表列,下標均從0開始;A[i][j]代表格子(i, j)處的蘋果數量。
S[i][j]有兩種計算方式:
1.對於每一行,從左向右計算,然後從上到下逐行處理;
2. 對於每一列,從上到下計算,然後從左向右逐列處理。這樣做的目的是為了在計算S[i][j]時,S[i-1][j]和S[i][j-1]都已經計算出來了。

#include <iostream>
using namespace std;
#define MAX_N 100
#define MAX_M 100
int arr[ MAX_N ][ MAX_M ] = { 0 };
int dp[ MAX_N + 2 ][ MAX_M + 2 ] = { 0 }; 
int main(){
	int n, m;
	cin>> n >> m;  //輸入n*m的方格
	int i, j ;
	for( i = 0; i < n; i++){
		for( j = 0; j < m; j++)
			cin>> arr[ i ][ j ];
	} //輸入方格中各個格子中的蘋果數量
	for( i = 0; i < n; i++){
		for( j = 0; j < m; j++){
			dp[ i + 1 ][ j + 1 ] = dp[ i ][ j + 1] > dp[ i + 1 ][ j ] ? 
						dp[ i ][ j + 1] + arr[ i ][ j ] : dp[ i + 1][ j ] + arr[ i ][ j ]; //動態規劃最重要的狀態轉移方程
		}
	} 
	cout<<dp[i][j]<<endl;
	return 0;
}