使用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 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值