【例3.6】過河卒(Noip2002)


【題目描述】

棋盤上A點有一個過河卒,需要走到目標B點。卒行走的規則:可以向下、或者向右。同時在棋盤上的某一點有一個對方的馬(如C點),該馬所在的點和所有跳躍一步可達的點稱為對方馬的控制點,如圖3-1中的C點和P1,……,P8,卒不能通過對方馬的控制點。棋盤用坐標表示,A點(0,0)、B點(n, m) (n,m為不超過20的整數),同樣馬的位置坐標是需要給出的,C≠A且C≠B。現在要求你計算出卒從A點能夠到達B點的路徑的條數。

【輸入】

給出n、m和C點的坐標。

【輸出】

從A點能夠到達B點的路徑的條數。

【輸入樣例】

8 6 0 4

【輸出樣例】

1617

【來源】

Noip2002

 

這個題是一道經典的老題一直都想寫一下,終於在一個伸手不見五指的夜晚如願以償,用時2個小時,調試時間過長,主要原因是腦子反應過慢。這個題有個很麻煩的地方是故意把坐標給混亂,想了半天終於有一種好的辦法,就是將原圖向左翻轉90度。如下圖:

這樣就不會混亂,坐標軸就與給定坐標對應。這個題的遞推邊界一定要考慮好,而且馬的控制點這一塊一定要細心,不然很容易出錯。

 

 1 #include<iostream>
 2 using namespace std;
 3 int n, m, cx, cy;
 4 long long f[40][40], g[40][40];//注意盡量使用long long不然容易超出數據范圍 
 5 int main()
 6 {
 7     cin>>n>>m>>cx>>cy;
 8     f[0][0]=1;
 9     //以下考慮馬的控制點有無越界 
10     g[cx][cy]=1;
11     if(cx-1>=0&&cy-2>=0)g[cx-1][cy-2]=1;
12     if(cx+1<=n&&cy-2>=0)g[cx+1][cy-2]=1;
13     if(cx-2>=0&&cy-1>=0)g[cx-2][cy-1]=1;
14     if(cx+2<=n&&cy-1>=0)g[cx+2][cy-1]=1;
15     if(cx-2>=0&&cy+1<=m)g[cx-2][cy+1]=1;
16     if(cx+2<=n&&cy+1<=m)g[cx+2][cy+1]=1;
17     if(cx-1>=0&&cy+2<=m)g[cx-1][cy+2]=1;
18     if(cx+1<=n&&cy+2<=m)g[cx+1][cy+2]=1;
19     
20     //以下為遞推邊界 
21     for(int i=1; i<=n; i++)
22         if(!g[i][0])f[i][0]=f[i-1][0];
23     for(int j=1; j<=m; j++)
24         if(!g[0][j])f[0][j]=f[0][j-1];
25     //以下為遞推關系式,相對簡單能想到    
26     for(int i=1; i<=n; i++)
27         for(int j=1; j<=m; j++)
28         {
29             if(g[i][j])f[i][j]=0;
30             if(!g[i][j])f[i][j]=f[i][j-1]+f[i-1][j];
31         }
32 //調試代碼所用
33 //    for(int i=0; i<=n; i++)
34 //    {
35 //        for(int j=0; j<=m; j++)cout<<f[i][j]<<" ";
36 //        cout<<endl;
37 //    }
38     cout<<f[n][m];
39     return 0;
40 }

 

 

 

另外這個題應該可以用到搜索,等講到搜索用搜索寫第二種方法,所以本篇文章未完待續。。。。。。

 

 

2018年10月2日晚,終於快該講搜索了,決定重新寫一下《過河卒》,用時10分鍾,代碼如下

 

 1 #include<cstdio>
 2 using namespace std;
 3 int cnt=0;//用於存儲路徑數 
 4 bool visd[30][30]={0};//用於標記坐標位置是否已經被搜索 0為沒有,1為訪問
 5 bool b[30][30]={0};//用於標記坐標點是否為馬的控制點,0為不是,1為是 
 6 int n, m, cx, cy;
 7 int next[2][2]={{1,0},{0,1}};
 8 void dfs(int x, int y)
 9 {
10     if(x==n && y==m)
11     {
12         cnt++;
13         return;
14     }
15     for(int i=0; i<2; i++)
16     {
17         int nx=x+next[i][0];
18         int ny=y+next[i][1];
19         if((nx>n) || (ny>m) || b[nx][ny])continue;//判斷下一步坐標是否越界 或是馬的控制點 
20         if(!visd[nx][ny] )
21         {
22             visd[nx][ny]=1;
23             dfs(nx,ny);
24             visd[nx][ny]=0;
25         }
26         
27     }
28 }
29 int main()
30 {
31     scanf("%d%d%d%d",&n,&m,&cx,&cy);
32     b[cx][cy]=1;
33     if(cx-1>=0&&cy-2>=0)b[cx-1][cy-2]=1;
34     if(cx+1<=n&&cy-2>=0)b[cx+1][cy-2]=1;
35     if(cx-2>=0&&cy-1>=0)b[cx-2][cy-1]=1;
36     if(cx+2<=n&&cy-1>=0)b[cx+2][cy-1]=1;
37     if(cx-2>=0&&cy+1<=m)b[cx-2][cy+1]=1;
38     if(cx+2<=n&&cy+1<=m)b[cx+2][cy+1]=1;
39     if(cx-1>=0&&cy+2<=m)b[cx-1][cy+2]=1;
40     if(cx+1<=n&&cy+2<=m)b[cx+1][cy+2]=1;
41     dfs(0,0);
42     printf("%d",cnt);
43     return 0;
44 }

 

評測結果如下:

顯然有數據超時,so我們遇到題搜索能得到一個正確的答案,但不一定能AK!需要分析他的復雜性!遞歸轉遞推是灰常重要的一種方法!請認真對比以上兩種算法實現方式!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM