例题6-14 UVa816-Abbott的复仇(BFS)

BFS的题目,值得学习的地方是灵活地使用数组来表示结点的各种状态,以及将定长的字符串转换成对应的数字以方便使用。先记录一点。

题目链接:UVa 816

AC代码:

#include 
#include 
#include 
using namespace std;

const char* dirs = "NESW";
const char* turns = "FLR";
const int dr[] = { -1,0,1,0 };
const int dc[] = { 0,1,0,-1 };  //dr、dc一一组合,对应向北东南西四个方向转弯
bool has_edge[20][20][8][8];  //表示在(r,c,dir)处向turn方向转是否可行
int d[20][20][8]; //表示(r,c,dir)到起点的最短路径长度
string s;
struct Node {
	int r, c, dir; //横坐标,纵坐标,转向
	Node(int a = 0, int b = 0, int d = 0) :r(a), c(b), dir(d) {}
}p[20][20][8], entrance, start, goal;  //p用来保存(r,c,dir)在BFS树中的父结点
ostream& operator <<(ostream& out, const Node& p) {
	out << "(" << p.r << "," << p.c << ")";
	return out;
}

int dir_id(char c) {
	return strchr(dirs, c) - dirs;
}
int turn_id(char c) {
	return strchr(turns, c) - turns;
}
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);
}
void input_read() {  //读入每个交叉点的信息
	memset(has_edge, false, sizeof(has_edge));
	int r, c, dir, turn;
	string str;
	while (cin >> r && r) {
		cin >> c;
		while (cin >> str && str[0] != '*') {
			dir = dir_id(str[0]);
			for (int i = 1; i < str.length(); i++) {
				turn = turn_id(str[i]);
				has_edge[r][c][dir][turn] = true;
			}
		}
	}
}
void print(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];
	}
	nodes.push_back(entrance);
	cout << s << endl;
	int cnt = 0;
	for (int i = nodes.size() - 1; i >= 0; i--) {
		if (!(cnt % 10)) cout << " ";
		cout << " " << nodes[i];
		if (!(++cnt % 10)) cout << endl;
	}
	if (nodes.size() % 10) cout << endl; //十的倍数的情况下已经输出过换行符了
}
void solve() {
	queue <Node> q;
	memset(d, -1, sizeof(d));
	memset(p, 0, sizeof(p));
	d[start.r][start.c][start.dir] = 0;
	q.push(start);
	while (!q.empty()) {
		Node u = q.front(); q.pop();
		if (u.r == goal.r && u.c == goal.c) {
			print(u);
			return;
		}
		for (int i = 0; i < 3; i++) {
			Node v = walk(u, i);
			if (has_edge[u.r][u.c][u.dir][i] && d[v.r][v.c][v.dir] < 0) { //可以访问到且还没被<<从当前方向v.dir>>访问
				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);
			}
		}
	}
	cout << s << endl << "  No Solution Possible" << endl;
}

int main() {
	while (cin >> s && s != "END") {
		char ch;
		cin >> entrance.r >> entrance.c >> ch >> goal.r >> goal.c;
		entrance.dir = dir_id(ch);
		start = walk(entrance, 0);
		input_read();
		solve();
	}
	return 0;
}

你可能感兴趣的:(第6章,数据结构基础)