您的位置:首页 > 其它

POJ 3083 Children of the Candy Corn(走迷宫)

2015-12-25 16:31 477 查看
题目链接:POJ 3083

题意:

给一个迷宫,‘#’代表墙,'.'代表可行,’S‘代表入口,’E‘代表出口。分别求出:

①按左、上、右、下顺序前行从入口到出口的步数。

②按右、上、左、下顺序前行从入口到出口的步数。

③从入口到出口的最短步数。

入口在边上但不在拐角处。入口和出口也各算一步。

分析:

最短路径直接用BFS求解。

先分析第一种要求,即左上右下的顺序,第二种与之类似。

入口在不同的边上下一步走的方向下标变化是不一样的。

①当srow=0时,顺序是: { 0,1 },{ 1,0 },{ 0,-1 },{ -1,0 };【入口在最上面一条边】

②当srow=h-1时,顺序是:{ 0,-1 },{ -1,0 },{ 0,1 },{ 1,0 };【入口在最下面一条边】

③当scol=0时,顺序是: { -1,0 },{ 0,1},{ 1,0 },{ 0,-1 };【入口在最左面一条边】

④当scol=w-1时,顺序是: { 1,0 },{ 0,-1 }, { -1,0 },{ 0,1}。【入口在最右边一条边】
仔细观察可以发现:①和②其实是同一个序列【相对顺序是一样的】,③和④是同一个序列。所以可以分两类方向逐个查找,沿右上左下顺序前行也是同样的道理。

在方向上还有一点需要考虑。拿测试一来说,移动的顺序是:

(7,1)->(6,1)->(5,1)->(4,1)->(3,1)->(2,1)->(1,1)->(1,2)->(1,3)->......

注意:(1,1)之前的搜索方向顺序是:{ 0,-1 },{ -1,0 },{ 0,1 },{ 1,0 };转向后,

从(1,2)开始搜索方向顺序变为:{ -1,0 },{ 0,1 },{ 1,0 },{ 0,-1 }。通过多写几组下标变化对比可以发现规律:用dfs传递的方向下标是:(当前方向下标+3)%4

难点:

搜索方向的确定

dfs传递的参数:下一搜索点,下一次开始搜索方向下标,移动步数,搜索方向数组
找到出口时返回的是step+1
在dfs函数里有两个return:找到出口和return dfs(...)。

参考链接:POJ 3083



#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 41;
char s[maxn];
int vis[maxn][maxn],a[maxn][maxn];
int n, w, h, x, y, newx, newy, t;
int srow, scol, erow, ecol, startindex;
//srow,scol,erow,ecol分别是起点终点下标,startindex是开始探索方向下标
int ansbfs, ansleft, ansright;
int flag = 0;

int dirleft1[4][2] = { { 0,1 },{ 1,0 },{ 0,-1 },{ -1,0 } };
int dirleft2[4][2] = { { -1,0 },{ 0,1},{ 1,0 },{ 0,-1 } };
int dirright1[4][2] = { { 0,-1 },{ 1,0 },{ 0,1 },{ -1,0 } };
int dirright2[4][2] = { { 1,0 },{ 0,1 },{ -1,0 },{ 0,-1 } };
int dfs(int x, int y, int k, int step, int dir[4][2])
{
	for (int i = 0;i < 4;i++)
	{
		t = (k + i) % 4;//这样避免了方向下标越界
		newx = x + dir[t][0];
		newy = y + dir[t][1];
		if (newx == erow&&newy == ecol) return step+1;//+1是因为终点也算一个
		if(newx < 0 || newy < 0 || newx >= h || newy >= w || a[newx][newy]||(newx==srow&&newy==scol)) continue;
		//下标不能越界;遇墙跳过;不能再去起点
		return dfs(newx, newy, (t+3)%4, step + 1, dir);
		//因为下一次再从左/右边开始时可能已经‘转向’了,例如测试一里从(1,1)到(1,2),所以这里要传递(t+3)%4,而不是k
	}
}

int dirbfs[4][2] = { {1,0},{-1,0},{0,1},{0,-1} };
struct Node {
	int a;
	int b;
	int step;
}cur,nextnode;
int bfs()
{
	queue<Node> q;
	cur.a = srow;
	cur.b = scol;
	cur.step = 1;
	vis[cur.a][cur.b] = 1;
	q.push(cur);
	while (!q.empty())
	{
		cur = q.front();
		q.pop();
		for (int i = 0;i < 4;i++)
		{
			x = cur.a + dirbfs[i][0];
			y = cur.b + dirbfs[i][1];
			if (x < 0 || y < 0 || x >= h || y >= w || vis[x][y] || a[x][y]) continue;
			nextnode.a = x;
			nextnode.b = y;
			nextnode.step = cur.step + 1;
			vis[x][y] = 1;
			if (x == erow&&y == ecol) return cur.step+1;
			q.push(nextnode);
		}
	}
}

int main()
{
#ifdef LOCAL
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	cin >> n;
	while (n--)
	{
		cin >> w >> h;
		for (int i = 0;i < h;i++)
		{
			cin >> s;
			for (int j = 0;j < w;j++)
			{
				if (s[j] == '#') a[i][j] = 1;//a[i][j]=1代表墙
				else if (s[j] == '.') a[i][j] = 0;
				else if (s[j] == 'S')
				{
					a[i][j] = 0;
					srow = i;
					scol = j;
				}
				else if (s[j] == 'E')
				{
					a[i][j] = 0;
					erow = i;
					ecol = j;
				}
			}
		}
		ansbfs = ansleft = ansright = 0;
		if (srow == 0 || srow == h - 1)
		{
			if (srow == 0) startindex = 0;
			else startindex = 2;
			ansleft = dfs(srow, scol, startindex, 1, dirleft1);
			ansright = dfs(srow, scol, startindex, 1, dirright1);
		}
		else if(scol==0||scol==w-1)
		{
			if (scol == 0) startindex = 0;
			else startindex = 2;
			ansleft = dfs(srow, scol, startindex, 1, dirleft2);
			ansright = dfs(srow, scol, startindex, 1, dirright2);
		}
		memset(vis, 0, sizeof(vis));
		ansbfs = bfs();
		cout << ansleft<<" "<<ansright<<" "<<ansbfs << endl;
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: