Abbott‘s Revenge

本文探讨了一种迷宫求解算法及其实际应用案例,包括作者Robert Abbott创造的走迷宫箭头迷宫,详细介绍了算法实现过程、输入输出格式、解决复杂迷宫的方法,并分析了迷宫求解与最短路径问题的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

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 year’s problem statement. But we are happy to report that Mr. Abbott has offered his expertise to this year’s 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 intersection 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. But if there are several solutions which are equally long, you can chose any of them.

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.

The first maze in the following sample input is the maze in Figure 1.



Sample InputOutput for the 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
  (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



Figure 1: An Example Walk-Through Arrow Maze



Figure 2: Robert Abbott’s Atlanta Maze


Robert Abbott’s 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 display 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 intended to be walked through.

For the adventurous, Figure 2 is a graphic of Robert Abbott’s 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 himself indicated that the maze is too complex and most people give up before finishing. Among the people that did not give up was Donald Knuth: it took him about thirty minutes to solve the maze.

很多复杂的迷宫问题都可以转化为最短路问题,然后用BFS求解。BFS一般借助队列来实现。此题的思路如下:
1.首先是几个重要数组:用数组has_edge【r】【c】【dir】【i】来存放位于r,c处,方向为dir时,可否转向方向i。用数组p【】【】【】来存放r,c,dir的“父结点”。用数组q【】【】【】来标记这个路口是否走过。
2.接下来是几个函数:walk函数来计算当前状态下的后记状态。solve函数进行BFS。print_out函数进行输出(借助vector)。
3.此题再一次用到了构造函数,关于这个函数,如果是在定义一个结构体类型的变量的时候,构造函数会自动被调用,进行赋初值。而如果像walk函数一样直接使用了它,只是要构造一个结构体,通俗来说就是我要return一个结构体类型的值,因为它不像int类型,它是由多个值组成的,所以我需要调用构造函数来像系统声明我所返回的值是结构体类型的。代码如下:
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;

int r0,c0,r1,c1,r2,c2,dir;
int has_edge[10][10][5][4],d[10][10][5]; 

struct Node
{
	int r,c,dir;
	Node(int r=0,int c=0,int dir=0):r(r),c(c),dir(dir){}
};
Node p[10][10][5];

const char* pos="NESW";
const char* turn="FLR";

int id_pos(char c){return strchr(pos,c)-pos;} 
int id_turn(char c){return strchr(turn,c)-turn;}

const int dr[]={-1,0,1,0};
const int dc[]={0,1,0,-1};

bool read_in()
{
	char s1[25],s2[3];
	if(scanf("%s%d%d%s%d%d",s1,&r0,&c0,s2,&r2,&c2)!=6) return false;  //虽然只有一个字母,但仍用s2读入,防止读入空格。
	printf("%s\n",s1);
	dir=id_pos(s2[0]);
	r1=r0+dr[dir];
	c1=c0+dc[dir];
	int m,n;
	memset(has_edge,0,sizeof(has_edge));
	while(scanf("%d",&m)==1&&m)
	{
		scanf("%d",&n);
		while(scanf("%s",s1)==1&&s1[0]!='*')
		{
			for(int i=1;i<strlen(s1);i++)
			has_edge[m][n][id_pos(s1[0])][id_turn(s1[i])]=1;
		}
	}
	return true;
}
Node walk(const Node u,int turn)
{
	int dir=u.dir;
	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);
}
int inside(int r,int c)
{
	return r>=1&&r<=9&&c>=1&&c<=9;
}

void print_out(Node u)
{
	vector<Node> ve;
	for(;;)
	{
		ve.push_back(u);
		if(d[u.r][u.c][u.dir]==0) break;
		u=p[u.r][u.c][u.dir];
	}
	ve.push_back(Node(r0,c0,dir));
	int ans=0;
	for(int i=ve.size()-1;i>=0;i--)
	{
		if(ans%10==0) printf(" ");
		printf(" (%d,%d)",ve[i].r,ve[i].c);
		if((++ans)%10==0) printf("\n");
	}
	if(ve.size()%10!=0) printf("\n");
}

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值