广度优先算法 越狱

问题描述

建筑师迈克尔为了救含冤入狱的哥哥,自己也想办法进了监狱。现在他找到了哥哥,想带着哥哥越狱。

可是监狱地形复杂,还有一道道的电网拦在面前。

电网非常危险,不到无路可走,迈克尔都不想尝试钻过电网。

请帮迈克尔兄弟设计一条穿过电网最少的路线。

(只能往相邻的四个方向前进)

输入

第一行:N,表示地图的大小(10 <= N <= 1000)

接下来N行N列,表示地图,1表示有电网,0表示没有,以空格隔开。

起点(1,1) 和终点(N, N) 一定没有电网。

输出

求到达终点最少穿过的电网数。

需要注意的是,穿越紧挨在一起的两个1,是穿过了两道电网,而不是穿过了“1道厚度为2的电网”。

样例输入

10

0  0  0  0  1  1  0  1  1  1

1  0  1  0  1  0  1  1  0  1

0  0  0  0  1  0  1  0  1  1

1  1  1  1  1  1  0  1  1  0

1  0  0  0  0  0  0  1  1  0

0  0  1  1  1  1  1  1  0  0

0  0  1  0  0  0  0  1  1  1

0  0  0  0  1  0  0  0  0  0

1  0  0  1  1  1  0  1  1  1

0  1  0  0  0  0  1  0  1  0

样例输出

2

分析

这题的数据量比较大,达到1000,假如使用DFS,光沿着边走,就已经到达2000,递归达到2000层,栈是绝对会爆的。

所以这题考虑使用BFS进行遍历。而思路则是,一开始找出被1包围的区域,走到无路可走时,进行突破,result+1;

突破之后继续寻找下一个被1包围的区域,直到到达终点。

具体做法则是,使用双队列,一个存放0,一个存放1。在BFS的时候,把需要访问的0放入0队列,1放入1队列。

当0队列为空时,表示无路可走。这时清空0队列,把1队列数据转移到0队列作为下一次BFS的数据。如此循环直到访问到右下角的终点

代码

#include <stdio.h>

using namespace std;

#define MAX 1002
#define DEBUG 0

typedef struct _NODE_ {
	unsigned int x;
	unsigned int y;
}st_node;

int N;
char map[MAX][MAX];
int result = 0;
st_node list0[MAX*MAX];  //数组太小会导致越界
st_node list1[MAX*MAX];

void BFS (st_node node) {
	st_node tmp;
	int head0 = 0, tail0 = 0;
	int head1 = 0;
	
	list0[head0++] = node;	   //in_queue

	while(tail0 <= head0) {
		node = list0[tail0++]; //out_queue

		for (int i = 0; i < 4; i++) {
			tmp = node;

			if (i == 0) {         //向下
				tmp.x++;
			} else if (i == 1) {  //向上
				tmp.x--;
			} else if (i == 2) {  //向右
				tmp.y++;
			} else if (i == 3) {  //向左
				tmp.y--;
			}

			if ( map[ tmp.x ][ tmp.y ] == 2 ) {       // 已访问
				continue;
			} else if ( map[ tmp.x ][ tmp.y ] == 0 ) { // 进入0队列
				list0[ head0++ ] = tmp;
				map[ tmp.x ][ tmp.y ] = 2;

			} else if ( map[ tmp.x ][ tmp.y ] == 1 ) { // 进入1队列
				list1[ head1++ ] = tmp;
				map[ tmp.x ][ tmp.y ] = 2;
			}
		}

		if ( tail0 == head0 ) {	//找到被1包围的区域,必须突破区域

			result++;    //增加需要突破的电网数目
#if DEBUG 
			for (int x = 0; x <= N+1; x++) {
				for (int y = 0; y <= N+1; y++) {
					printf("%d ", map[x][y]);
				}
				printf("\n");
			}
#endif
			//将1队列的数据复制到0队列,作为下一次BFS的数据
			for (int i = 0; i < head1; i++) {
				list0[i] = list1[i];
			}

			head0 = head1;
			tail0 = head1 = 0;
		}

		if (map[N][N] == 2)
			break;
	}
}

int main(int argc, char *argv[])
{

#if DEBUG 
	freopen("input.txt","r", stdin);
#endif

	scanf("%d", &N);

	int edge = N + 1;
	for ( int i = 0; i <= edge; i++ ) {
		map[0][i] = 2;
		map[i][0] = 2;
		map[edge][i] = 2;
		map[i][edge] = 2;
	}
	
	int tmp = 0;
	for ( int i = 1; i <= N; i++ ) {
		for ( int j = 1; j <= N; j++ ) {
			scanf("%d", &tmp);
			map[i][j] = tmp;
		}
	}	


	st_node node;
	node.x = 1;
	node.y = 1;

	BFS(node);

	printf("%d", result);

    return 0;
}

点赞