(水)POJ-3083 按规定方向遍历方法

题目大意:给一个图,需求3个解,第一个和第二个分别为按照一定原则走到E的步数,规则为规定人有一个面向,第一个答案为依次按左前右后遍历所需步数,第二个为依次按右前左后遍历所需步数,其中前后左右都是以当前面向为参考系。第三个解为最短路。下面给出求第一个解时的走法的实例:


我用0,1,2,3分别来代表西,北,东,南。假设我们从3的位置走到了当前位置,那么面向肯定是朝向1即朝向北方的,此时我们的左,前,右,后分别指的是0,1,2,3方向。

题目链接:点击打开链接

分析:我们在dfs时可以用一个参数q记下当前的面向,然后按照相对于当前面向q的4个方向左前右上遍历便行了。具体方法请看代码,有注释。

附上代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f3f
#define judge(x,y) a[x][y]=='.'&&!vis[x][y]
struct point{ int x, y; point(int a = 0, int b = 0){ x = a, y = b; } };
using namespace std;
char a[45][45];
int d[45][45];
bool vis[45][45];
int _move[4][2] = { { 0, -1 }, { -1, 0 }, { 0, 1 }, { 1, 0 } };
int n, m, ans1, ans2, ans3;
int sx, sy;
int ex, ey;
int dfs(int x,int y,int q,int kase)   //q为当前面向,kase为第一种或者第二种走法的特定的值,当执行左优先走法时kase为3,右优先走法时为1,具体分析请往下看
{
	if (x == ex&&y == ey) return 1;
	int res = 0;
	for (int i = q + kase; i < q + kase + 4 * (4 - kase); i += 4 - kase)  //这里我们只分析左优先走法,右优先读者请自行分析。当左优先走法时,若当前面向为q,则(q+3)%4即为当前面向的左面,读者请根据图中给出的方向想一想为什么。左优先时当尝试完上一种方向i时,则下一种方向为i+1。
	{
		int fx = x + _move[i % 4][0], fy = y + _move[i % 4][1];
		if (judge(fx, fy))
		{
			res = dfs(fx, fy, i % 4, kase) + 1;
			break;
		}
	}
	return res;
}
int bfs()   //bfs求最短路,dfs会超时
{
	d[sx][sy] = 0;
	queue<point> q;
	q.push(point(sx, sy));
	vis[sx][sy] = 1;
	while (!q.empty())
	{
		point v = q.front();
		q.pop();
		for (int i = 0; i < 4; i++)
		{
			int fx = v.x + _move[i][0], fy = v.y + _move[i][1];
			if (judge(fx, fy))
			{
				q.push(point(fx, fy));
				d[fx][fy] = d[v.x][v.y] + 1;
				if (fx == ex&&fy == ey) return d[fx][fy];
				vis[fx][fy] = 1;
			}
		}
	}
	return 0;
}
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		memset(d, 0x3f3f3f3f, sizeof d);
		memset(a, false, sizeof a);
		memset(vis, false, sizeof vis);
		scanf("%d%d", &m, &n);
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
			{
				cin >> a[i][j];
				if (a[i][j] == 'S') { sx = i, sy = j; }
				if (a[i][j] == 'E') { ex = i, ey = j; a[i][j] = '.'; }
			}
		int q;
		if (sx == 1) q = 3;      //确认处于S处的初始面向
		else if (sx == n) q = 1;
		else if (sy == 1) q = 2;
		else q = 0;   
		ans1 = dfs(sx, sy, q, 3);
		ans2 = dfs(sx, sy, q, 1);
		ans3 = bfs() + 1;      //+1的原因为结果一共经历过哪些地方,包括起点,而不是走了多少步
		printf("%d %d %d\n", ans1, ans2, ans3);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值