1. 程式人生 > >Openjudge 2728 摘花生(二維DP入門)

Openjudge 2728 摘花生(二維DP入門)

描述

Hello Kitty 想摘點花生送給她喜歡的米老鼠。她來到一片有網格狀道路的矩形花生地(如下圖),從西北角進去,東南角出來。地裡每個道路的交叉點上都有種著一株花生苗,上面有若干顆花生,經過一株花生苗就能摘走該它上面所有的花生。Hello Kitty只能向東或向南走,不能向西或向北走。問Hello Kitty 最多能夠摘到多少顆花生。


輸入
第一行是一個整數T,代表一共有多少組資料。1<=T <= 100
接下來是T組資料。
每組資料的第一行是兩個整數,分別代表花生苗的行數R和列數 C ( 1<= R,C <=100)
每組資料的接下來R行資料,從北向南依次描述每行花生苗的情況。每行資料有 C 個整數,按從西向東的順序描述了該行每株花生苗上的花生數目 M ( 0<= M <= 1000)。
輸出


對每組輸入資料,輸出一行,內容為Hello Kitty能摘到得最多的花生顆數。
樣例輸入
2
2 2
1 1
3 4
2 3
2 3 4
1 6 5
樣例輸出
8

16

#include <stdio.h>
#include <string.h>
int max(int a,int b)
{
	return a>b?a:b;
}
int main ()
{
	int t,buf[105][105]={0};
	scanf ("%d",&t);
	while (t--){
		int m,n;
		scanf ("%d%d",&m,&n);
		int i,j;
		for (i = 1;i <= m;i++){
			for (j = 1;j <= n;j++){
				scanf ("%d",&buf[i][j]);
			}
		}
		for (i = n;i > 0;i--){
			for (j = m;j > 0;j--){
				buf[j][i] += max(buf[j][i+1],buf[j+1][i]);
			}
		}
		printf ("%d\n",buf[1][1]);
		memset(buf,0,sizeof buf);
	}
	return 0;
}

這道題可以說是和經典的數字三角形一模一樣了。都是一種求找到一種路徑,求所經過路徑的權值之和最大。其特點是起點固定不變。並且行走路徑具有不可逆性(只能向東或向南走。又如數字三角形只能向下走不能返回)。

從數字三角形來說:從頂點到最後一排的走法如果列舉的可能性太多了!其實只需要考慮每一行當前一點是否選擇走。選擇的依據便是,走當前這個點的收益是多大?顯然下一步有兩種走法,則選擇最大收益的那個走法(buf[i][j]+=max(buf[i+1][j],buf[i+1][j+1])本身這個點+往下能走到的點中最大的點便是走這個點的最大收益)。所以可以從後向前的去遞推這一步的收穫最大的值知道最後必然得到頂點的收穫值是最大的(假如得到第四層的最大收益,那麼依據這一行便可以同理遞推出上一行的最大收益)。

輸入的資料


遞推之後的dp資料


那麼這題摘花生也是類似,但是摘花生是二維圖。從什麼方向遞推回去呢?答案是和數字三角形一樣從反方向遞推。

963
852
741
表格中數字代表列舉遞推的順序。
987
654
321

這樣的遞推順序也是可以的,只要與題目要求的行走方向相反即可(在水平方向與向東走的規則相反,在豎直方向上與向南走的方向相反)