1. 程式人生 > >【遞推】過河卒

【遞推】過河卒

【題目描述】

如圖,A 點有一個過河卒,需要走到目標 B 點。卒行走規則:可以向下、或者向右。同時在棋盤上的任一點有一個對方的馬(如上圖的C點),該馬所在的點和所有跳躍一步可達的點稱為對方馬的控制點。例如上圖 C 點上的馬可以控制 9 個點(圖中的P1,P2 … P8 和 C)。卒不能通過對方馬的控制點。


【輸入】
 鍵盤輸入
B點的座標(n,m)以及對方馬的座標(X,Y){不用判錯}
【輸出】
 螢幕輸出
 一個整數(路徑的條數)。
【樣例輸入】
6 6 3 2
【樣例輸出】
17
【AC程式碼】

#include<iostream>
#include<cstdio>    //用scanf(),printf()輸入輸出加快速度
#include<cstring>    //cstring內有memset()函式
using namespace std;
int a[9]={0,-1,-1,-2,-2,1,1,2,2};    //陣列a[]儲存馬控制的橫座標範圍
int b[9]={0,2,-2,1,-1,2,-2,1,-1};    //陣列b[]儲存馬控制的縱座標範圍,注意相同下標的a,b之間有一定的對應關係,即除了(0,0)外|a|與|b|一個為1,另一個為2
int n,m,x,y,i,j;
int map[21][21];    //map[i][j]表示地圖上(i,j)這個點是否是馬的控制點
long long tripnum[21][21];    //tripnum[i][j]表示從(0,0)到(i,j)卒合法的行走路線總數
int main()
{
	memset(tripnum,0,sizeof(tripnum));
	scanf("%d%d%d%d",&n,&m,&x,&y);
	for(i=0;i<=20;i++)
		for(j=0;j<=20;j++)
			map[i][j]=1;    //map[i][j]為1時表示(i,j)非控制點
	for(i=0;i<=8;i++)
		if(x+a[i]<=20 && x+a[i]>=0 && y+b[i]<=20 && y+b[i]>=0)    //如果控制點在地圖範圍內,即這個點存在
			map[x+a[i]][y+b[i]]=0;    //將其設為0,表示這裡被馬控制
	for(j=0;j<=20;j++)    //從左到右遍歷最上面一行的所有點
		if(map[0][j]==1)    //如果這個點不是控制點
			tripnum[0][j]=1;    //那麼從(0,0)到達這個點的路線自然只有一條
		else    //否則這點不可到達,路線數為初值0條
			break;    //並且其右的點也不可達,不必繼續遍歷
	for(i=0;i<=20;i++)    //從上到下遍歷最左邊一列的所有點
		if(map[i][0]==1)    //如果這個點不是控制點
			tripnum[i][0]=1;    //那麼從(0,0)到達這個點的路線自然只有一條
		else    //否則這點不可到達,路線數為初值0條
			break;    //並且其下的點也不可達,不必繼續遍歷
	for(i=1;i<=n;i++)    //從(1,1)這個點開始,逐行的去看(也可以逐列)
		for(j=1;j<=m;j++)
			if(map[i][j]==1)    //如果這個點不是控制點
				tripnum[i][j]=tripnum[i-1][j]*map[i-1][j]+tripnum[i][j-1]*map[i][j-1];    //那麼到達它的路線數等於其左的點路線與其上的點之和,由於其左與其上的點有可能是控制點,所以要乘以控制係數map[i][j](這也是為什麼用0代表控制,而用1代表非控制,而不是調換過來的原因)
	printf("%lld",tripnum[n][m]);
return 0;
}