Abbott 的复仇(Abbott's Revenge,ACM|IPPC World Finals 2000, UVa 816)

代码如下:

#include <iostream>
#include <queue>
using namespace std;

//const char * dirs = "NESW";
//const char * turns = "FLR";
const int N = 0, E = 1, S = 2, W = 3;
const int F = 0, L = 1, R = 2;

//分别表示N(上),E(右),S(下),W(左)
const int dr[] = {-1, 0, 1, 0};
const int dc[] = {0, 1, 0, -1};

//移动的角色有三个属性(行,列,方向)
typedef struct Node
{
	Node(){}
	Node(int row, int col, int d):r(row), c(col), dir(d){}
	int r;
	int c;
	int dir;
}Node;

int END_POINT_ROW = 3;
int END_POINT_COL = 3;

/*
 *p[0][0][]的情况是浪费的空间,因为坐标是从p[1][1][]开始; 
 *d[0][0][]的情况是浪费的空间,因为坐标是从d[1][1][]开始
 *has_edge[0][0][]的情况是浪费的空间,因为坐标是从has_edge[1][1][][]开始
 */
Node p[4][4][4];	//保存的是父节点(行,列,方向);建立终点往回找的线索
int d[4][4][4];		//标记当前节点是否走过
bool has_edge[4][4][4][3] = {0};	//保存角色下一步能走的方向(FLR)

//判断角色是否越界了
bool inside(int r, int c)
{
	if(3 == r && 1 == c || 3 == r && 3 == c) return true;
	if(r >= 1 && r <= 2 && c >= 1 && c <= 3) return true;
	return false;
}

//通过前一点的移动方向,得到下一点的位置
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 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];
	}
	//nodes.push_back(Node(r0, c0, dir));
	Node nodeBegin(3, 1, N);
	nodes.push_back(nodeBegin);

	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);
	Node u(2, 1, N);
	d[u.r][u.c][u.dir] = 0;
	q.push(u);
	while(!q.empty())
	{
		Node u = q.front(); q.pop();
		if(u.r == END_POINT_ROW && u.c == END_POINT_COL) { 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 Soulution\n");
}

int main()
{
	memset(has_edge, 0, sizeof(has_edge));
	//设置约束条件,规定在某个点上,角色只能往某几个方向走
	//如下,规定(3,1)朝北的角色只能向前(F)走
	has_edge[3][1][N][F] = true;

	has_edge[2][1][N][F] = true; 
	has_edge[2][1][S][L] = true; 
	has_edge[2][1][W][R] = true; 

	has_edge[1][1][N][R] = true; 
	has_edge[1][1][W][L] = true; 

	has_edge[1][2][E][R] = true; 
	has_edge[1][2][W][F] = true; 
	has_edge[1][2][W][L] = true; 
	has_edge[1][2][N][R] = true; 

	has_edge[2][2][E][F] = true; 
	has_edge[2][2][E][L] = true; 
	has_edge[2][2][S][L] = true; 
	has_edge[2][2][W][F] = true; 

	has_edge[1][3][E][R] = true; 
	has_edge[1][3][N][L] = true; 

	has_edge[2][3][E][L] = true; 
	has_edge[2][3][S][F] = true; 
	has_edge[2][3][S][R] = true; 

	has_edge[3][3][S][F] = true; 
	solve();
	return 0;
}

输出:


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值