POJ 3083 BFS

39 篇文章 0 订阅

题目地址:http://poj.org/problem?id=3083

题目大意: 说有一个迷宫,迷宫有一个入口S和出口E,现在要你求出三种路径各自的长度

1. 沿着最左边走。

2. 沿着最右边走。

3. 最短路径。

其实沿着最左,最右方向走的时候,特别需要小心的是考虑在顺时针和逆时针转的时候,当前方向,选择下一个位置,和下一个方向之间的关系。

为了更好的解释,我用图说明一下:



1. 沿着最左边走:

当沿着最左边缘的墙壁行走的时候,每次搜索的方向都是从当前方向的左边,然后按照逆时针的方向进行搜索的。

不妨我们将搜索的四个点用数组表示 SearchDirection: (0, -1), (1,0), (0, 1), (-1, 0). 


假如当前遍历的 点是(r,c). 

假设当前行走方向是 UP,那么对应最左是 SearchDirection[0], 按照合法性搜索 0, 1, 2, 3;

如果当前行走方向是RIGHT, 那么最左是SearchDirection[1], 合法搜索方向是 1, 2, 3, 0.

                                    DOWN,                        SearchDirection[2],                               2, 3, 1, 0

                                    LEFT                            SearchDirection[3],                              3, 0, 1, 2


根据初始方向容易决定搜索方向和搜索起始点,但是如何决定搜索以后的下一个方向呢。

如果当前选择了, SearchDirection[0] -> 则对应最后的LEFT

                              SearchDirection[1] -> UP

                              SearchDirection[2] -> RIGHT

                              SearchDirection[3] -> DOWN

假设初始方向是  enum {UP, RIGHT, DOWN, LEFT} 表示的 d, 选择的searchDirection是 i,那么最后的方向就是 dNew  = i + 3;


对于逆时针有类似的属性。


关于最短路径这里,也有一些想法吧,最开始用DFS做了一下,发现结果超时了。

后来用BFS做了一下,就AC了。


其实做了几个题目以后,个人感觉可达性问题是比较适合用DFS解决的,而最短路径就比较适合用BFS解决。

提到最短路径就时常会想起 Dijkstra,这个算法是解决单源最短路径的经典算法,不过它针对的是更通用的问题,就是说每个边的权重是一个整数,并且没有负数环。

而这里问题是很简单的,根据两点的拓扑可达性,距离只有0 和 1,所以利用BFS解决是更合理的方法。

在DFS中,回溯过程会所搜索很多空间,并不适合求最短路径。而BFS因为在求解的过程中,将遍历的过的节点不再继续遍历,所以会有比较高的效率。


代码如下:

#include <stdio.h>
#include <memory.h>
#define MAX_GRID 45

struct Grid
{
	int r;
	int c;

	int nSteps;

	Grid(int _r, int _c)
	{
		r = _r;
		c = _c;
		nSteps = 0;
	}
	Grid()
	{
		nSteps = 0;
	}
};

bool operator == (const Grid&a, const Grid &b)
{
	return a.r == b.r && a.c == b.c;
}
bool operator != (const Grid &a,const Grid&b)
{
	return (a.r != b.r) || (a.c != b.c);
}

Grid g_Neighbors[4] = 
{ Grid(0, -1), Grid(-1,0), Grid(0, 1), Grid(1, 0)
};

enum Direction{UP = 0, RIGHT, DOWN, LEFT};
int g_Yard[MAX_GRID][MAX_GRID];
int nCol, nRow;

Grid GetNewPoint(const Grid ¤tGrid, int iNeighbor)
{
	Grid g = Grid(currentGrid.r + g_Neighbors[iNeighbor].r, currentGrid.c + g_Neighbors[iNeighbor].c);
	return g;
}
void GetLeftMost(const Grid ¤tGrid, Direction d, Grid &nextGrid, Direction &nextdirection )
{
	int iStart = (int)d;
	Grid g;
	for( int i = 0; i < 4; i++)
	{
		g = GetNewPoint(currentGrid, (iStart + i)%4);
		if(g_Yard[g.r][g.c] == 1)
		{
			continue;
		}
		else
		{
			nextGrid = g;
			nextdirection = Direction(((int)d + i + 3)%4);
			break;
		}
	}
}
void GetRightMost(const Grid ¤tGrid, Direction d, Grid &nextGrid, Direction &nextdirection)
{
	int iStart = ((int)d + 2)%4;

	Grid g;

	for( int i = 4; i > 0; i--)
	{
		g = GetNewPoint(currentGrid, (iStart + i)%4);
		if(g_Yard[g.r][g.c] == 1)
		{
			continue;
		}
		else
		{
			nextGrid = g;
			nextdirection = Direction(((int)d + i + 1)%4);
			break;
		}

	}

}

Direction GetInitialDirection(const Grid &start)
{
	if(start.r == 0)
	{
		return DOWN;
	}
	if(start.r == nRow - 1)
	{
		return UP;
	}
	if(start.c == 0)
	{
		return RIGHT;
	}
	if(start.c == nCol - 1)
	{
		return LEFT;
	}
}
int findStepsForLeftmost(const Grid &start, const Grid &exit)
{
	Direction d = GetInitialDirection(start);
	int nSteps = 1;
	Grid currentGrid = start, nextGrid;
	while( currentGrid != exit)
	{
		GetLeftMost(currentGrid, d,nextGrid, d);
		currentGrid = nextGrid;
		nSteps ++;
	}
	return nSteps;

}
int findStepsForRightmost(const Grid &start, const Grid &exit)
{
	Direction d = GetInitialDirection(start);
	int nSteps = 1;
	Grid currentGrid = start, nextGrid;
	while( currentGrid != exit)
	{
		GetRightMost(currentGrid, d,nextGrid, d);
		currentGrid = nextGrid;
		nSteps ++;
	}
	return nSteps;

}


Grid q[2000];


bool GridLegal(const Grid &g)
{
	if( g.r < 0 || g.r >= nRow || g.c < 0 || g.c >= nCol || g_Yard[g.r][g.c] == 1)
	{
		return false;
	}
	return true;
}
int BFS(const Grid &start, const Grid & exit)
{

	int front, rear;
	front = rear = 0;

	q[rear++] = start;
	
	while(rear > front)
	{
		Grid top = q[front];
		
		if(top == exit)
		{
			return top.nSteps;
		}
		//iterate the neighboring 
		for(int i = 0; i < 4; i++)
		{
			Grid neighbor = GetNewPoint(top, i);
			if(GridLegal(neighbor))// not visited
			{
				g_Yard[neighbor.r][neighbor.c] = 1;
				neighbor.nSteps = top.nSteps + 1;
				q[rear++] = neighbor;
			}
		}

		front++;
	}
	return -1;

}

int main()
{


	int nCase;
	scanf("%d", &nCase);
	while(nCase--)
	{


		scanf("%d%d", &nCol, &nRow);
		int i,j;
		char c;
		memset(g_Yard, 0, sizeof(g_Yard));
		Grid start, exit;

		for( i = 0; i < nRow; i++)
		{
			getchar();

			for( j = 0; j < nCol; j++)
			{
				c = getchar();
				if( c == '#')
				{
					g_Yard[i][j] = 1;
				}
				else if( c == 'S')
				{
					start.r = i;
					start.c = j;
					g_Yard[i][j] = 1;
				}
				else if( c == 'E')
				{
					exit.r = i;
					exit.c = j;
				}
			}
		}

		int minSteps = 10000000;
		int leftmost = findStepsForLeftmost(start, exit);
		int rightmost = findStepsForRightmost(start, exit);

		minSteps = BFS(start, exit);
		printf("%d %d %d\n",leftmost ,rightmost, minSteps+1);

	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值