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

题目链接: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;
}




根据提供的引用内容,可以得知这是一道关于迷宫问题的题目,需要使用Java语言进行编写。具体来说,这道题目需要实现一个迷宫的搜索算法,找到从起点到终点的最短路径。可以使用广度优先搜索或者深度优先搜索算法来解决这个问题。 下面是一个使用广度优先搜索算法的Java代码示例: ```java import java.util.*; public class Main { static int[][] maze = new int[5][5]; // 迷宫地图 static int[][] dir = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; // 方向数组 static boolean[][] vis = new boolean[5][5]; // 标记数组 static int[][] pre = new int[5][5]; // 记录路径 public static void main(String[] args) { Scanner sc = new Scanner(System.in); for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { maze[i][j] = sc.nextInt(); } } bfs(0, 0); Stack<Integer> stack = new Stack<>(); int x = 4, y = 4; while (x != 0 || y != 0) { stack.push(x * 5 + y); int t = pre[x][y]; x = t / 5; y = t % 5; } stack.push(0); while (!stack.empty()) { System.out.print(stack.pop() + " "); } } static void bfs(int x, int y) { Queue<Integer> qx = new LinkedList<>(); Queue<Integer> qy = new LinkedList<>(); qx.offer(x); qy.offer(y); vis[x][y] = true; while (!qx.isEmpty()) { int tx = qx.poll(); int ty = qy.poll(); if (tx == 4 && ty == 4) { return; } for (int i = 0; i < 4; i++) { int nx = tx + dir[i][0]; int ny = ty + dir[i][1]; if (nx >= 0 && nx < 5 && ny >= 0 && ny < 5 && maze[nx][ny] == 0 && !vis[nx][ny]) { vis[nx][ny] = true; pre[nx][ny] = tx * 5 + ty; qx.offer(nx); qy.offer(ny); } } } } } ``` 该代码使用了广度优先搜索算法,首先读入迷宫地图,然后从起点开始进行搜索,直到找到终点为止。在搜索的过程中,使用标记数组记录已经访问过的位置,使用路径数组记录路径。最后,使用栈来输出路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值