Abbott's Revenge (uva816)BFS+最短路(ACM/ICPC World Final 2000 A)

原题目:

The 1999 World FinalsContest included a problem based on a “dicemaze.” At the time the problem was written, the judges were unable todiscover the original source of the dice maze concept. Shortly afterthe contest, however, Mr. Robert Abbott, the creator of numerous mazesand an author on the subject, contacted the contest judges andidentified himself as the originator of dice mazes. We regret that wedid not credit Mr. Abbott for his original concept in last year’sproblem statement. But we are happy to report that Mr. Abbott hasoffered his expertise to this year’s contest with his original andunpublished “walk-through arrow mazes.” 
As are most mazes, awalk-through arrow maze is traversed by moving from intersection tointersection until the goal intersection is reached. As eachintersection is approached from a given direction, a sign near theentry to the intersection indicates in which directions theintersection can be exited. These directions are always left, forwardor right, or any combination of these. 
Figure 1 illustrates awalk-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 youapproach from the south indicates that you may exit (1,1) only bymaking 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 isalso 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 havethe option of continuing straight or turning left. Continuing straightwould take you on toward (1,1), while turning left would take you southto (2,2). The actual (unique) solution to this maze is the followingsequence 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 programto solve valid walk-through arrow mazes. Solving a maze means (ifpossible) finding a route through the maze that leaves the Entrance inthe prescribed direction, and ends in the Goal. This route should notbe longer than necessary, of course. But if there are several solutionswhichare equally long, you can chose any of them.

Input

The input file willconsist of one or more arrow mazes. The first line of each mazedescription contains the name of the maze, which is an alphanumericstring of no more than 20 characters. The next line contains, in thefollowing order, the starting row, the starting column, the startingdirection, the goal row, and finally the goal column. All are delimitedby a single space. The maximum dimensions of a maze for this problemare 9 by 9, so all row and column numbers are single digits from 1 to9. The starting direction is one of the characters N, S, E or W,indicating north, south, east and west, respectively. 
All remaining inputlines for a maze have this format: two integers, one or more groups ofcharacters, and a sentinel asterisk, again all delimited by a singlespace. The integers represent the row and column, respectively, of amaze intersection. Each character group represents a sign at thatintersection. The first character in the group is N, S, E or W toindicate in what direction of travel the sign would be seen. Forexample, S indicates that this is the sign that is seen when travellingsouth. (This is the sign posted at the north entrance to theintersection.) Following this first direction character are one tothree arrow characters. These can be L, F or R indicating left,forward, and right, respectively. 
The list ofintersections is concluded by a line containing a single zero in thefirst column. The next line of the input starts the next maze, and soon. The end of input is the word END on a single line by itself.

 

Output

For each maze, theoutput file should contain a line with the name of the maze, followedby 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 allother 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 thesolution should contain exactly 10 intersections. 
The first maze in thefollowing sample input is the maze in Figure 1.

 

Sample Input

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

 

Sample Output

(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)

【分析】

本题和普通的迷宫在本质上是一样的,但是由于朝向也起到关键作用,所以需要用一个三元组(r,c,dir)表示位于(r,c),面朝dir的状态,假设入口位置为(r0,c0)朝向位置为dir,则初始状态并不是(r0,c0,dir)而是(r1,c1,dir),其中,(r1,c1)是(r0,c0)沿着方向dir走一步之后的坐标,此处用d[r][c][dir]表示初始状态到(r,c,dir)的最短路长度,并且用p[r][c][dir]保存了状态(r,c,dir)在BFS树中的父节点

其中has-edge[r][c][dir][turn]表示当前状态(r,c,dir),是否可以沿着转弯方向turn行走

#include<algorithm>
#include<vector>
#include<queue>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct Node{
	int r, c, dir;// 站在(r,c),面朝方向dir(0~3分别表示N, E, S, W)
	Node(int r = 0, int c = 0, int dir = 0) :r(r), c(c), dir(dir) {}//构造函数,用来初始化
};
const char* dirs = "NESW";
const char* turns = "FLR";
int dir_id(char c){
	return strchr(dirs, c) - dirs;
}
int turn_id(char c) {
	return strchr(turns, c) - turns;
}
const int dr[] = { -1,0,1,0 };
const int dc[] = { 0,1,0,-1 };
const int MAX = 10;
int has_edge[MAX][MAX][4][3];//保存每一个坐标的具体转向方式
int d[MAX][MAX][4];//用来累加起点到终点的距离
Node p[MAX][MAX][4];//p[r][c][dir]表示了(r,c,dir)在BFS树中的父节点
int r0, r1, r2, c0, c1, c2, dir;
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);
}
bool inside(int r, int c) {//判断是否出界
	return r >= 1 && r <= 9 && c >= 1 && c <= 9;
}
void print_ans(Node u) {//从目标结点逆序追溯到初始结点
	vector<Node> nodes;
	for (;;) {
		nodes.push_back(u);
		if (d[u.r][u.c][u.dir] == 0) {//表示找到终点
			break;
		}
		u = p[u.r][u.c][u.dir];//表示u为u的父节点
	}
	nodes.push_back(Node(r0, c0, dir));
	//开始打印,每行10个
	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 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 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 (has_edge[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");
}
bool read_case() {
	char s[99], s2[99];
	//s是指当前的流程,r0表示起始行,c0表示起始列,s2起始方向,r2表示目标行,c2表示目标列
	if (scanf("%d%d%s%d%d", &r0, &c0, s2, &r2, &c2) != 5) return false;

	dir = dir_id(s2[0]);//方向在字符串dirs中的位置
	r1 = r0 + dr[dir];//第一步之后的行坐标
	c1 = c0 + dc[dir];//第二步之后的列坐标

	memset(has_edge, 0, sizeof(has_edge));
	for (;;) {
		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++)
				has_edge[r][c][dir_id(s[0])][turn_id(s[i])] = 1;
		}
	}
	return true;
}
int main() {
	while (read_case()) {
		solve();
	}
	return 0;
}

太尼玛麻烦了,看懂并敲一遍耗费了我一下午。。。

不过这个样例都没问题,就是一直wa,看评论说貌似这个卡最后一个空格???

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

deebcjrb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值