1. 程式人生 > 實用技巧 >動態規劃----洛谷P1002 過河卒題解

動態規劃----洛谷P1002 過河卒題解

一些廢話

第一次遇見動態規劃是在大一下學期剛轉完專業時小學期的練習題,對於當時剛學完C語言語法的我來說,動態規劃簡直就是天書。今天刷題的時候又見到動態規劃,於是隨手寫一篇學習筆記記錄一下動態規劃的學習過程。


引言

動態規劃的基本概念,請您自行谷歌,反正看了也沒用,不會的人怎麼琢磨基本概念都琢磨不出來。

之前在某個論壇上看見一位同學的想法:動態規劃不就是遞迴演算法加上記憶功能嗎?對,動態規劃並不難,就是遞迴和記憶。

通過記憶之前完成的計算,從而能得出本次計算的結果,這就是動態規劃。


例子

動態規劃最經典的例子就是斐波那契數列了,所謂斐波那契數列,就是f(i)=f(i-1)+f(i-2),所以只要知道f(i-1)和f(i-2)的值,就能得到f(i)的值了。

看,這就是動態規劃,通過記憶之前的結果,通過遞迴的形式,得到現在的結果。

而動態規劃的題目,都可以用這種思想來解決。

下面附上三個非常經典的動態規劃的題目


題目描述

樓梯有NN階,上樓可以一步上一階,也可以一步上二階。

編一個程式,計算共有多少種不同的走法。

輸入格式

一個數字,樓梯數。

輸出格式

輸出走的方式總數。

分析

假設我們現在在第五層,那麼我們之前一步可能位於的位置就是第三層或者第四層,所以上到第五層的可能方法就是上到第三層的可能方法加上上到第四層的可能方法的和,因此可以得出f(i)=f(i-1)+f(i-2),這是最簡單的一個動態規劃了,下面我們來看看稍微難一點的一道題


題目描述

你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。

給定一個代表每個房屋存放金額的非負整數陣列,計算你 不觸動警報裝置的情況下 ,一夜之內能夠偷竊到的最高金額。

輸入格式

1 2 3 1

輸出格式

4

解釋

偷竊 1 號房屋 (金額 = 1) ,然後偷竊 3 號房屋 (金額 = 3),最高金額就是4

分析

當我們考慮要不要偷這個房子的時候,首先要想,(假如我們在第五家的門口)如果偷了這家,那我們只能偷第三家之前的,如果不偷,我們可以偷第四家之前的。偷不偷取決於本次偷竊加上第三家之前的偷竊的總和 和 第四家之前的偷竊的金額做對比,誰大選誰。

因此我們要比較max((totalmoney(3)+money(5)),totalmoney(4)),最終的值,作為f(5)記錄下來,保證每一家的(可能的)偷竊都最大化,最終,到達最後一家時,可以保證偷竊效益最大化(因為前面所有的記錄的金額都是最大化收益,自然,最後一家的偷竊也是最大化收益)


題目描述

棋盤上AA點有一個過河卒,需要走到目標BB點。卒行走的規則:可以向下、或者向右。同時在棋盤上CC點有一個對方的馬,該馬所在的點和所有跳躍一步可達的點稱為對方馬的控制點。因此稱之為“馬攔過河卒”。

棋盤用座標表示,AA點(0, 0)(0,0)、BB點(n, m)(n,m),同樣馬的位置座標是需要給出的。

現在要求你計算出卒從AA點能夠到達BB點的路徑的條數,假設馬的位置是固定不動的,並不是卒走一步馬走一步。

輸入格式

一行四個正整數,分別表示BB點座標和馬的座標。

輸出格式

一個整數,表示所有的路徑條數。

分析

先不要害怕題目的複雜度,我們來分析:每次你走到的位置只有可能從上面或者左面走到,不可能從下面或者右面走(那是腦子有病才那麼走),所以,你每一個位置可能的路徑,就是上面的格子可能路徑加上下面格子可能路徑的和!

另外,馬所控制的9個格子,他們的路徑數都應該特殊設定為0!因為不可以走到那個路徑上!

好了,這題就這麼簡單,分析結束了,本題有必要上程式碼,一些多餘的解釋和提醒我也寫在程式碼裡了

 1 #include<iostream>
 2 using namespace std;
 3 long long dp[100][100];//記錄路徑數目,需要開long long因為數字很大 
 4 bool s[100][100];//用於標記馬所控制的位置 
 5 int fx[] = {0, -2, -1, 1, 2, 2, 1, -1, -2};//便於計算馬的位置 
 6 int fy[] = {0, 1, 2, 2, 1, -1, -2, -2, -1};
 7 int main()
 8 {
 9     int bx,by,hx,hy;
10     cin>>bx>>by>>hx>>hy;
11     for(int i=0;i<9;i++)//把馬所在的九個位置全特殊標記 
12     {
13         if(hx+fx[i]<0||hy+fy[i]<0||hx+fx[i]>bx||hy+fy[i]>by)//這裡要注意,如果馬控制的位置超出邊界了,就不要計算了 
14         {
15             continue;
16         }
17         s[hx+fx[i]][hy+fy[i]]=1;
18     }
19     for(int i=0;i<=bx;i++)//把邊界先填上,以便於計算 
20     {
21         if(s[i][0])
22         {
23             dp[i][0]=0;
24             break;//這裡要注意是break而不是continue,因為自從那個點以後,下面的所有點,都不能通過了,都是0! 
25         }
26         else
27         {
28             dp[i][0]=1;
29         }
30     }
31     for(int i=0;i<=by;i++)
32     {
33         if(s[0][i])
34         {
35             dp[0][i]=0;
36             break;//同上,需要注意 
37         }
38         else
39         {
40             dp[0][i]=1;
41         }
42     }
43     for(int i=1;i<=bx;i++)//計算除邊界外的每一個點的可能路徑數 
44     {
45         for(int j=1;j<=by;j++)
46         {
47             if(s[i][j])//如果被馬佔領,這個位置的路徑數是0 
48             {
49                 dp[i][j]=0;
50             }
51             else
52             {
53                 dp[i][j]=dp[i-1][j]+dp[i][j-1];
54             }
55         }
56     }
57     cout<<dp[bx][by];//最終輸出終點的可能性 
58  } 


到這裡差不多就結束了,以上就是一些簡單的動態規劃的題目和思路

因為本人也是一名初學者,所以只能提供一些見過的題目的例子,希望本篇隨筆對您有所幫助。