馬攔過河
【問題描述】
棋盤上A點有一個過河卒,需要走到目標B點。卒行走的規則:可以向下、或者向右。同時在棋盤上C點有一個對方的馬,該馬所在的點和所有跳躍一步可達的點稱爲對方馬的控制點。因此稱之爲“馬攔過河卒”。
棋盤用座標表示,A點(0, 0)、B點(n, m)(n, m爲不超過15的整數),同樣馬的位置座標是需要給出的。現在要求你計算出卒從A點能夠到達B點的路徑的條數,假設馬的位置是固定不動的,並不是卒走一步馬走一步。
【輸入】
一行四個數據,分別表示B點座標和馬的座標。
【輸出】
一個數據,表示所有的路徑條數。
【樣例】
knight.in knight.out
6 6 3 36
【解析】
這是一個看似簡單,實則是不那麼簡單的題,現在我只會簡單的方法,等我有空把再把不簡單的方法整出來,簡單的方法就是遞歸,款搜、深搜。
遞歸算法:
pascal代碼:
varn,m,horse_x,horse_y:integer;
k:longint;
i,j:integer;
control:array[-2..17,-2..17] of boolean;
a:array[1..8,1..2] of integer=((-1,-2),(-2,-1),(1,2),(2,1),(-1,2),(2,-1),(-2,1),(1,-2));
procedure try(x,y:integer);
begin
if (x=n) and (y=m) then
begin
inc(k);
exit; end;
if (x+1<=n) and not control[x+1,y] then try(x+1,y);
if (y+1<=m) and not control[x,y+1] then try(x,y+1);
end;
begin
readln(n,m,horse_x,horse_y);
fillchar(control,sizeof(control),0);
k:=0;
for i:=1 to 8 do control[horse_x+a[i,1],horse_y+a[i,2]]:=true;
control[horse_x,horse_y]:=true;
try(0,0);
writeln(k);
end.
C++代碼:
#include <iostream>
using namespace std;
int n,m,horse_x,horse_y;
int i,j,k;
int a[8][2]={{-1,-2},{-1,2},{-2,-1},{-2,1},{1,-2},{1,2},{2,-1},{2,1}};
bool control[16][16]={0};
void horse(int x,int y)
{
if ((x==n)&&(y==m))
{
++k;
return;
}
if ((x+1<=n) && (!control[x+1][y])) {horse(x+1,y);}
if ((y+1<=m) && !control[x][y+1] ){horse(x,y+1);}
};
int main()
{
cin>>n>>m>>horse_x>>horse_y;
for (i=0;i<8;i++)
{
if ((horse_x+a[i][0]<=n)&&(horse_x+a[i][0]>=0)&&(horse_y+a[i][1]<=m)&&(horse_y+a[i][1]>=0))
control[horse_x+a[i][0]][horse_y+a[i][1]]=true;
}
control[horse_x][horse_y]=true;
horse(0,0);
cout<<k<<endl;
system("pause");
return 0;
}
上面兩種寫法都是遞歸,但是兩者在細節上處理上有點小不同,如c++代碼裏的紅色那塊加了個限制條件,而pascal裏沒有,那是因爲我在pascal裏定義control數組時故意把範圍擴大了,所以不存在溢出的問題,而c++的下標只能從0開始,所以必須加上紅色的限制條件,不然很可能出現數組越界的問題
遞歸調用的方法,可想而知效率肯定不會理想,但是這個題其實可以優化到n^2!!對了,此題有個條件和經典的動歸數字三角形有驚人相似之處“卒行走的規則:可以向下、或者向右”,所以當前狀態時有其左邊和上邊得來,但是有點麻煩的是有個噁心的馬,那怎麼辦呢,簡單,直接把這個馬的控制點全置爲零不就解決問題了嗎??所以動歸方程爲:f[i][j]=f[i-1][j]+f[i][j-1],f[i][j]表示從起點能到達(i,j)的路徑條數,不過這題要注意要處理邊界條件,即當i-1或j-1小於零是的狀態,同時f[0][0]=1。代碼如下只寫了c++代碼,
#include <iostream>
using namespace std;
int n,m,horse_x,horse_y;
int i,j,k;
bool flag[16][16];
int a[8][2]={{-1,-2},{-1,2},{-2,-1},{-2,1},{1,-2},{1,2},{2,-1},{2,1}};
int f[16][16]={0};
int main()
{
cin>>n>>m>>horse_x>>horse_y;
memset(flag,true,sizeof(flag));
flag[horse_x][horse_y]=false;
for(i=0;i<8;i++)
{
if ((horse_x+a[i][0]<=n)&&(horse_x+a[i][0]>=0)&&(horse_y+a[i][1]>=0)&&(horse_y+a[i][1]<=m))
{
flag[horse_x+a[i][0]][horse_y+a[i][1]]=false;
}
}
f[0][0]=1;
for (i=0;i<=n;i++)
{
for(j=0;j<=m;j++)
{
if (i-1<0&&j-1>=0&& flag[i][j]) f[i][j]=f[i][j-1];
if (i-1>=0&& j-1<0 && flag[i][j]) f[i][j]=f[i-1][j];
if(i-1>=0&&j-1>=0&&flag[i][j]) f[i][j]=f[i-1][j]+f[i][j-1];
}
}
cout<<f[n][m]<<endl;
system("pause");
return 0;
}
雖然時間效率上去了,如果n,m過大的話注意要用高精度,不然……&……