標籤:
路徑經過的最大值(最小值):
原題:平面上有N*M個格子,每個格子中放著一定數量的蘋果。從左上方的格子開始, 每一步只能向下走或是向右走,每次走到一個格子就把格子裡的蘋果收集起來, 這樣一直走到右下角,問最多能收集到多少個蘋果。
不妨用一個表格來表示:
{5, 8, 5, 7, 1, 8},
{1, 3, 2, 8, 7, 9},
{7, 8, 6, 6, 8, 7},
{9, 9, 8, 1, 6, 3},
{2, 4,10, 2, 6, 2},
{5, 5, 2, 1, 8, 8},
在這個6X6的表格裡面填寫了一些數表示所在格子中的蘋果數量。根據題目的規則"每一步只能向下走或是向右走",如果用x表示縱向,用y表示橫向,那麼能夠到達a[x,y]處的只有兩個位置a[x-1,y](上一格)和a[x,y-1](左邊一格),所以必然是取這兩個位置中比較大的那一個點。依此回溯到a[0,0],或者從a[0,0]遞推到a[x,y]。
......... , ......... , a[x-1,y]
......... , a[x,y-1], a[x,y] ,
基於這一點,我們可以從左上方開始將到達第一行和第一列中各點所能收集到的最大蘋果數量填成一張表格。如下:
接下來填第2行,首先是第2行第2列的值,應該填寫為 MAX(A[1,2], A[2,1])+ A[2,2]對應的蘋果數量。也就是說到達第2行第2列能獲得的最大蘋果數,要看第2行第1列所獲得的蘋果數(6)和第1行第2列所獲得的蘋果數(13),這兩者哪個更大,誰大就取誰的值,顯然第1行第2列所獲得的蘋果數(13)更大,所以用13加上第2行第2列的蘋果數3 = 16,就是到達第2行第2列能獲得的最大蘋果數。同理,填所在格能獲得的最大蘋果數就是看它左面一格和上面一格哪個值更大,就取哪個值再加上自己格子裡面的蘋果數,就是到達此格能獲得的最大蘋果數。依此填完所有格子,最後得到:
所以:到達右下角能夠獲得的最大蘋果數量是76。所經過的路徑可以通過反向推算的方法得到,從右下角開始看所在格子的左邊一格和上面一格哪邊大就往哪邊走,如果遇到一樣大的,任選一條即可。
這樣我們可以畫出路線圖,如右邊表格:
這個例子的分析和解決方案大概就是這樣了。在前面第一個例子裡面我們提到:空間換時間是動態規劃的精髓。但是一個問題是否能夠用動態規划算法來解決,需要看這個問題是否能被分解為更小的問題(子問題)。而子問題之間是否有包含的關係,是區別動態規划算法和分治法的所在。一般來說,分治法的各個子問題之間是相互獨立的,比如折半尋找(二分尋找)、歸併排序等。而動態規划算法的子問題在往下細分為更小的子問題時往往會遇到重複的子問題,我們只處理同一個子問題一次,將子問題的結果儲存下來,這就是動態規劃的最大特點。
動態規划算法總結起來就是兩點:
1 尋找遞推(遞迴)關係,比較專業的說法叫做狀態轉移方程。
2 儲存中間狀態,空間換時間。
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace SeqListSort{ /// <summary> /// <ather> /// lihonglin /// </ather> /// <content> /// 平面上有N*M個格子,每個格子中放著一定數量的蘋果。你從左上方的格子開始,每一步只能向下走或是 /// 向右走,每次走到一個格子上就把格子裡的蘋果收集起來,這樣一直走到右下角,你最多能收集到多少個蘋果。 ///輸入: ///第一行輸入行數和列數 ///隨機產生每個格子的中的蘋果的數量 ///輸出:最多能收到的蘋果的個數。 /// ///思路分析:這是一個典型的二維數組DP問題 ///基本狀態:當你到達第x行第y列的格子的時候,收集到的蘋果的數量dp[x,y]。 ///轉移方程:由於你只能向右走或者向下走,所以當你到達第x行第y列的格子的時候,你可能是從第x-1行第 ///y列或者第x行第y-1列到達該格子的,而我們最後只要收集蘋果最多的那一種方案。 ///所以:dp[x,y] = max( if(x>0) dp[x-1,y] , if(y>0) dp[x,y-1]) /// </content> /// </summary> class Apple_DP { static int[,] a = new int[100,100]; static int[,] dp = new int[100,100]; static int m,n; static void CollectApple(int x,int y) { dp[x, y] = a[x, y]; int max = 0; if (x > 0 && max < dp[x - 1, y])// 上邊一格 終點是x,y { max = dp[x - 1, y]; } if (y > 0 && max < dp[x, y - 1])// 左邊一格 終點是x,y { max = dp[x, y - 1]; } dp[x, y] += max; if(x < m - 1) { CollectApple(x + 1, y); } if(y < n - 1) { CollectApple(x, y + 1); } } public static void InitMap() { Console.WriteLine("請輸入m行,n列"); m = Convert.ToInt32(Console.ReadLine()); n = Convert.ToInt32(Console.ReadLine()); Random r = new Random(); for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { //a[i,j] = r.Next(1,m + n); Console.Write("{0,-3}", a[i, j] = r.Next(1, m + n)); } Console.WriteLine(); } CollectApple(0, 0); // 列印結果 for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { Console.Write("{0,-3}", dp[i, j]); } Console.WriteLine(); } } }}
動態規劃之收集蘋果