uva 816 有点复杂的BFS和宽度优先搜索模板 Abbott's Revenge

The 1999 World Finals Contest included a problem based on a dice maze. At the time the problem
was written, the judges were unable to discover the original source of the dice maze concept. Shortly
after the contest, however, Mr. Robert Abbott, the creator of numerous mazes and an author on the
subject, contacted the contest judges and identified himself as the originator of dice mazes. We regret
that we did not credit Mr. Abbott for his original concept in last years problem statement. But we are
happy to report that Mr. Abbott has offered his expertise to this years contest with his original and
unpublished walk-through arrow mazes.
As are most mazes, a walk-through arrow maze is traversed by moving from intersection to inter-
section until the goal intersection is reached. As each intersection is approached from a given direction,
a sign near the entry to the intersection indicates in which directions the intersection can be exited.
These directions are always left, forward or right, or any combination of these.
Figure 1 illustrates a walk-through arrow maze. The intersections are identified as (row, column)
pairs, with the upper left being (1,1). The Entrance intersection for Figure 1 is (3,1), and the Goal
intersection is (3,3). You begin the maze by moving north from (3,1). As you walk from (3,1) to (2,1),
the sign at (2,1) indicates that as you approach (2,1) from the south (traveling north) you may continue
to go only forward. Continuing forward takes you toward (1,1). The sign at (1,1) as you approach from
the south indicates that you may exit (1,1) only by making a right. This turns you to the east now
walking from (1,1) toward (1,2). So far there have been no choices to be made. This is also the case as
you continue to move from (1,2) to (2,2) to (2,3) to (1,3). Now, however, as you move west from (1,3)
toward (1,2), you have the option of continuing straight or turning left. Continuing straight would take
you on toward (1,1), while turning left would take you south to (2,2). The actual (unique) solution to
this maze is the following sequence of intersections: (3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1)
(2,1) (2,2) (1,2) (1,3) (2,3) (3,3).
You must write a program to solve valid walk-through arrow mazes. Solving a maze means (if
possible) finding a route through the maze that leaves the Entrance in the prescribed direction, and
ends in the Goal. This route should not be longer than necessary, of course.
Input
The input file will consist of one or more arrow mazes. The first line of each maze description contains
the name of the maze, which is an alphanumeric string of no more than 20 characters. The next line
contains, in the following order, the starting row, the starting column, the starting direction, the goal
row, and finally the goal column. All are delimited by a single space. The maximum dimensions of
a maze for this problem are 9 by 9, so all row and column numbers are single digits from 1 to 9.
The starting direction is one of the characters N, S, E or W, indicating north, south, east and west,
respectively.
All remaining input lines for a maze have this format: two integers, one or more groups of characters,
and a sentinel asterisk, again all delimited by a single space. The integers represent the row and column,
respectively, of a maze intersection. Each character group represents a sign at that intersection. The
first character in the group is ‘N’, ‘S’, ‘E’ or ‘W’ to indicate in what direction of travel the sign would
be seen. For example, ‘S’ indicates that this is the sign that is seen when travelling south. (This is the
sign posted at the north entrance to the intersection.) Following this first direction character are one
to three arrow characters. These can be ‘L’, ‘F’ or ‘R’ indicating left, forward, and right, respectively.
The list of intersections is concluded by a line containing a single zero in the first column. The next
line of the input starts the next maze, and so on. The end of input is the word ‘END’ on a single line
by itself.
Output
For each maze, the output file should contain a line with the name of the maze, followed by one or more
lines with either a solution to the maze or the phrase ‘No Solution Possible’. Maze names should
start in column 1, and all other lines should start in column 3, i.e., indented two spaces. Solutions
should be output as a list of intersections in the format (R,C) in the order they are visited from the
start to the goal, should be delimited by a single space, and all but the last line of the solution should
contain exactly 10 intersections.
Note:
Figure 2: Robert Abbott’s Atlanta Maze
Robert Abbotts walk-through arrow
mazes are actually intended for large-scale
construction, not paper. Although his
mazes are unpublished, some of them have
actually been built. One of these is on dis-
play at an Atlanta museum. Others have
been constructed by the American Maze
Company over the past two summers. As
their name suggests these mazes are in-
tended to be walked through.
For the adventurous, Figure 2 a
graphic of Robert Abbotts Atlanta maze.
Solving it is quite difficult, even when
you have an overview of the entire maze.
Imagine trying to solve this by actually
walking through the maze and only seeing
one sign at a time! Robert Abbott him-
self indicated that the maze is too com-
plex and most people give up before fin-
ishing. Among the people that did not
give up was Donald Knuth: it took him
about thirty minutes to solve the maze.
Figure 1: An Example Walk-Through
Arrow Maz
The first maze in the following sample input is the maze

in Figure 1.


Sample Input


SAMPLE
3 1 N 3 3
1 1 WL NR *
1 2 WLF NR ER *
1 3 NL ER *
2 1 SL WR NF *
2 2 SL WF ELF *
2 3 SFR EL *
0
NOSOLUTION
3 1 N 3 2
1 1 WL NR *
1 2 NL ER *
2 1 SL WR NFR *
2 2 SR EL *
0

END


Sample Output


SAMPLE
(3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1) (2,1)
(2,2) (1,2) (1,3) (2,3) (3,3)
NOSOLUTION

No Solution Possible


题目长得让人绝望,本题对初学宽度优先搜索的人来说还是很难的,而且还出现在紫书中(lrj果然是大佬啊,膜拜orz),写这篇博客方便自己日后做BFS时能找到类似的模板。有紫书(算法竞赛入门经典第二版)的可以参考紫书。


题目的意思是在9*9的迷宫中给定起点终点求最短路径,但是不同的朝向有不同的走法这是需要注意的,由于字符串不如数字好操作,所以将朝向和转向分别编号0-3和0-2,dr,dc表示行走的方向,对应有如下关系:

dir0123
朝向NESW
方向
dr-1010
dc010-1

由于有朝向的因素,状态标不能只有坐标,用一个三元组(r,c,dir)表示位于(r,c)朝向dir。同样对标记访问d数组也用三元组进行标记。由于要打印路径所以开一个path数组记录父结点,同样是三元。

这里有一个注意的点是初始状态并不是(r0,c0,dir)而是走一步后的坐标(r1,c1,dir)。


BFS模板:

1.读取数据

2.建图操作(实际上hasedge数组在这里就是图)

3.BFS主过程{

queue<node> q;

初始化起点相关数据(如d数组,坐标朝向)

q.push(u);

while(!q.empty()){

node u=q.front();q.pop();

处理边界(如到达终点->直接return并处理相关数据)

for(对当前结点所有可能的前进方向进行尝试){

node v=next(u);//获取下一个结点

if(能走到下一个结点,在边界内,未访问过)//判断可达性条件

{

d(v)=d(u)+1;//统计路径长度并标记访问

p(v)=u;//记录父结点

q.push(v);

}

}

否则输出无解的情况

}


说了这么多都不如源码管用,下面贴代码:

#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<cstdio>
using namespace std;

#define maxn 100
#define LOCAL
#ifdef LOCAL
#pragma warning(disable:4996)
#endif

struct Node {//状态标
	int r, c, dir;
	Node(int R = 0, int C = 0, int DIR = 0) :r(R), c(C), dir(DIR) {}

} p[10][10][4];//path数组记录父节点

int d[10][10][4];//d数组标记是否访问过顺便还能统计路径长度
int hasedge[10][10][4][3];//对当前(r,c)坐标,朝向dir,转向turn,是否有边供以行走
//hasedge数组实际就是一个图

int r0, c0, r2, c2;//起点,终点坐标
int r1, c1, dir;//真起点和朝向

const char* dirs = "NESW";// 面朝的方向 顺时针 
const char* turns = "FLR";//转向
int dir_id(char c) { return strchr(dirs, c) - dirs; }//0上,1右,2下,3左
int turn_id(char c) { return strchr(turns, c) - turns; }//0直走,1左转,2右转
const int dr[] = { -1,0,1,0 };//顺时针顺序对应 NESW
const int dc[] = { 0,1,0,-1 };

Node walk(const Node& u, int turn) {//走到下一个结点
	int dir = u.dir;
	//  turn == 0  直走
	if (turn == 1) dir = (dir + 3) % 4;//逆时针 左转
	if (turn == 2) dir = (dir + 1) % 4;//顺时针 右转
	return Node(u.r + dr[dir], u.c + dc[dir], dir);// 返回下一个结点
}

bool inside(int r, int c) {//在迷宫边界之内
	if (r <= 9 && r >= 1 && c <= 9 && c >= 1)return true;
	else return false;
}

bool read_case() {
	char s[99], s1[99];
	if (scanf("%s%d%d%s%d%d", s, &r0, &c0, s1, &r2, &c2) != 6) return false;
	printf("%s\n", s);
	dir = dir_id(s1[0]);
	r1 = r0 + dr[dir];
	c1 = c0 + dc[dir];

	memset(hasedge, 0, sizeof(hasedge));
	while (1) {
		int r, c;
		scanf("%d", &r);
		if (r == 0)break;
		scanf("%d", &c);
		while (scanf("%s", s) == 1 && s[0] != '*') {
			for (int i = 1; i < strlen(s); i++) {
				hasedge[r][c][dir_id(s[0])][turn_id(s[i])] = 1;
			}
		}
	}
	return true;
}

void print_ans(Node u) {//打印路径
	vector<Node> nodes;
	while (1) {
		nodes.push_back(u);
		if (d[u.r][u.c][u.dir] == 0) break;//回到起点,结束
		u = p[u.r][u.c][u.dir];//得到父结点
	}
	nodes.push_back(Node(r0, c0, dir));//别忘了加入源点路径
	int cnt = 0;
	for (int i = nodes.size() - 1; i >= 0; i--) {
		if (cnt % 10 == 0) printf(" ");
		printf(" (%d,%d)", nodes[i].r, nodes[i].c);
		if (++cnt % 10 == 0)printf("\n");
	}
	if (nodes.size() % 10 != 0)printf("\n");
}

void BFS() {
	queue<Node>q;
	memset(d, -1, sizeof(d));
	Node u(r1, c1, dir);
	q.push(u);
	d[u.r][u.c][u.dir] = 0;
	while (!q.empty()) {
		Node u = q.front(); q.pop();
		if (u.r == r2&&u.c == c2) {
			print_ans(u); return;
		}
		for (int i = 0; i < 3; i++) {
			Node v = walk(u, i);
			if (hasedge[u.r][u.c][u.dir][i] && inside(v.r, v.c) && d[v.r][v.c][v.dir] < 0) {
				d[v.r][v.c][v.dir] = d[u.r][u.c][u.dir] + 1;
				p[v.r][v.c][v.dir] = u;
				q.push(v);
			}
		}
	}
	printf("  No Solution Possible\n");
}

int main() {

#ifdef LOCAL
	freopen("ACMinput.txt", "r", stdin);
#endif

	while (read_case()) BFS();

	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值