1. 程式人生 > >使用BFS,在二維地圖中,尋求特定走法的最短距離。

使用BFS,在二維地圖中,尋求特定走法的最短距離。

這個問題,是我從USACO Camelot問題中,抽出的一個小問題,比較典型。

在一個二維地圖中,給定一個初始點,和相應的行走規則,求從這個初始點可到達的點的最小步數。

舉個例子:(camelot問題中,knight的走法)

給出行走規則:

  如圖,行走規則共有8個,及從圖中的黑點到白點的8個行走路線,當然,在行走時,不能躍出地圖的邊界。

地圖大小,這裡假定為5*5的。

初始點,即為中間的那個黑點。

基本思想,及使用BFS,每次的層擴充套件,都將新增從此點(使用8個規則)可到達的點。

每一層都比上一層的距離 加一。

 

如上圖,這是一種假設的情形,從起始點開始,第一層只有4個點滿足(可到達條件,未出界條件,未被訪問條件(及沒進過佇列))。然後第二層依次的可達點可能會有3個,1個,0個(假設的示意圖),依次往下,直到佇列為空。

下面給出一個具體的形式化例子。

輸入定義:

兩行:第一行代表行和列,第二行代表起始點的座標

其中,行和列的編號從數字1開始

(例如)

8 8

4 4

輸出定義:

從行1,列1開始依次按先行後列的順序遞加。可達測輸出相應的距離,不可達則輸出N,中間以空格間隔,.到每行的末尾輸出換行。(規定,點到自身也為不可達,這僅為程式設計時好處理而已,及初始化時距離統一賦值為0,當bfs過程完後,仍為0及表示不可達)

(例如,當使用如上輸入,和規則 --- knight的走法

2 3 2 3 2 3 2 3 
3 4 1 2 1 4 3 2 
2 1 2 3 2 1 2 3 
3 2 3 N 3 2 3 2 
2 1 2 3 2 1 2 3 
3 4 1 2 1 4 3 2 
2 3 2 3 2 3 2 3 
3 2 3 2 3 2 3 4 

 下面是C語言實現程式碼

#include<stdio.h>
#include<string.h>
#include<stdlib.h>


#define MAXX 20
#define MAXY 20

//在這裡定義規則
int dx[8]= {2,2,1,1,-2,-2,-1,-1};
int dy[8]= {-1,1,-2,2,-1,1,-2,2};
//第二個規則
//int dx[1] = {1};
//int dy[1] = {1};

int visit[MAXX][MAXY];
long d[MAXX][MAXY][MAXX][MAXY];

int m,n;

void bfsPath(int sx,int sy)
{
    int q[2][1000];
    int head, tail, i, tx, ty;
    memset(q, 0, sizeof(q));
    memset(visit, 0, sizeof(visit));
    head = 0;
    tail = 1;
    q[0][tail] = sx;
    q[1][tail] = sy;
    visit[sx][sy] = 1;
    
    while ( head<tail )
    {
        head++;
        tx = q[0][head];
        ty = q[1][head];
        for (i=0; i<8; i++)  //every level 當規則改變是,每次深搜的邊界值要變,如使用第二個規則,8 要變為 1
            if( tx+dx[i]>=1 && tx+dx[i]<=n && ty+dy[i]>=1 && ty+dy[i]<=m && !visit[tx+dx[i]][ty+dy[i]])
            {
		//put into the queue
                tail++;
                q[0][tail] = tx+dx[i];
                q[1][tail] = ty+dy[i];
		//mark
                visit[tx+dx[i]][ty+dy[i]] = 1;
                d[sx][sy][q[0][tail]][q[1][tail]] = d[sx][sy][tx][ty] + 1;
            }
    }
}


int main(void)
{
   
    int startX, startY;
    
    int i, j;
    
    scanf("%d %d", &n, &m);
    scanf("%d %d", &startX, &startY);

 
    memset(d, 0, sizeof(d));

    bfsPath(startX, startY);

    for (i=1; i<=n; i++){
	for (j=1; j<=m; j++)
	{
		if (d[startX][startY][i][j] == 0)
			printf("N ");
		else
			printf("%d ", d[startX][startY][i][j]);

		
	}
        printf("\n");
     }


    return 0;
}</span>


在舉例中,knight的走法可以訪問每一個點(自身除外),但有些規則是不能訪問到每個點的。

下面將規則變為 只能按(+1,+1)的規則走:

輸入:

8 8
4 4

輸出:
N N N N N N N N 
N N N N N N N N 
N N N N N N N N 
N N N N N N N N 
N N N N 1 N N N 
N N N N N 2 N N 
N N N N N N 3 N 
N N N N N N N 4