1. 程式人生 > 其它 >洛谷 P1002 [NOIP2002 普及組] 過河卒

洛谷 P1002 [NOIP2002 普及組] 過河卒

題目連結 https://www.luogu.com.cn/problem/P1002


 

一道入門的dp問題。

初始位置為(0,0),有點兒麻煩,改為(1,1),所以所有座標的位置全部+1。

卒到達的每一個位置都是從此位置的上方和左方走過來的。那麼假設卒從(1,1)到達此點的左方點的路徑有x條,到達此點的上方點的路徑有y條,則到達此點的路徑有x+y條。

那麼可以得到狀態轉移方程:dp[i][j]=dp[i-1][j]+dp[i][j-1],所以最終的答案被儲存在dp[n][m](假設B的座標為(n,m))。

需要注意的是需要對dp[1][1]或dp[2][0]進行初始化=1,否則無論走到哪個點其結果都是0。(令dp[2][1]=1按道理也是可以的,我也是這麼寫的)。

接下來開始迴圈計算到達每個點有幾條路徑。當遇到馬和馬能到達的點時就跳過。在這之前需要將馬所在的點和馬能到達的位置初始化,用來判斷。


 

放AC的程式碼

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int bx,by,mx,my;
 4 long long int dp[40][40];
 5 int s[40][40];
 6 int main()
 7 {
 8     cin>>bx>>by>>mx>>my;
 9     bx+=2; by+=2; mx+=2; my+=2
;//防止越界,並且假設A點為(1,1) 10 dp[2][1]=1; 11 s[mx][my]=1;//標記馬的位置以及馬能到達的點 12 s[mx-2][my-1]=1; s[mx-2][my+1]=1; 13 s[mx-1][my-2]=1; s[mx-1][my+2]=1; 14 s[mx+1][my-2]=1; s[mx+1][my+2]=1; 15 s[mx+2][my-1]=1; s[mx+2][my+1]=1; 16 for(int i=2;i<=bx;i++) 17 { 18 for(int j=2;j<=by;j++)
19 { 20 if(s[i][j]) continue;//如果此點被標記則跳過 21 dp[i][j]=dp[i-1][j]+dp[i][j-1];//狀態轉移方程 22 } 23 } 24 cout<<dp[bx][by]; 25 return 0; 26 }

 

當然,還可以優化。用滾動陣列可以節省空間。

因為我們只用到第i行和第i-1行的答案,所以可以只定義dp[2][1]就好了。

如何只保留第i和第i-1行的答案?取模。i=>i%2,i-1=>(i-1)%2。

此外,因為是滾動陣列 , 所以如果當前位置被馬攔住了一定要記住清零。


 

另,學到了一個新知識:

x%2可以在程式碼中寫成更快的運算方式x&1。

如果x是偶數,那麼x&1=0,如果x是奇數,那麼x&1=1。


 

放AC程式碼

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int bx,by,mx,my;
 4 long long dp[40][40];
 5 int s[40][40];
 6 int main()
 7 {
 8     cin>>bx>>by>>mx>>my;
 9     bx+=2; by+=2; mx+=2; my+=2;
10     dp[1][2]=1;
11     s[mx][my]=1;
12     s[mx-2][my-1]=1; s[mx-2][my+1]=1;
13     s[mx-1][my-2]=1; s[mx-1][my+2]=1;
14     s[mx+1][my-2]=1; s[mx+1][my+2]=1;
15     s[mx+2][my-1]=1; s[mx+2][my+1]=1;
16     for(int i=2;i<=bx;i++)
17     {
18         for(int j=2;j<=by;j++)
19         {
20             if(s[i][j])
21             {
22                 dp[i&1][j]=0;
23                 continue;
24             }
25             dp[i&1][j]=dp[(i-1)&1][j]+dp[i&1][j-1];
26         }
27     }
28     cout<<dp[bx&1][by];
29     return 0;
30 }