HDU 1728 逃离迷宫 http://acm.hdu.edu.cn/showproblem.php?pid=1728
对于代码32行,为什么等于不能随便剪掉
如果剪掉就会出现下图结果:
【假如转弯数k=1,起点终点如图】
那么如果你的代码是优先向右搜索就会出错
红色的线是先搜的,由于最多转一次弯,所以不合题意;
蓝色是后搜的,因为遇到转弯数相等所以不往下走了了,但是继续走是可以满足题意输出"yes"的
深搜:
#include
using namespace std;
#define inf 0x3fffffff//无穷大
#define M 105//数组大小
//1、wan用于转弯数剪枝;2、step用于步数兼职,就不用visit标记访问了
int r,c,ex,ey,k,wan[M][M];//行数,列数,终点x,终点y,弯数
char map[M][M];//接收控制台字符串
int x_move[4] = {-1, 0, 1, 0};//四方向移动
int y_move[4] = {0, 1, 0, -1};//四方向移动
bool flag; //判断成功
void dfs(int x,int y,int dir)//dir 为当前方向
{
if(x==ex&&y==ey)
{
if(wan[x][y]<=k)
flag=true;
return ;
}
if(wan[x][y]>k)//转弯数超过k不再往下走
return;
//x!=ex && y!=ey 说民必须至少转一次弯,但是已经不能再转了
if(wan[x][y]==k&&x!=ex&&y!=ey)
return ;
for (int i=0;i<4;i++)
{
int tx=x+x_move[i];
int ty=y+y_move[i];
if(tx<0||tx>=r||ty<0||ty>=c)//若出界
continue;
//转弯数相等不再剪枝,所以wan[tx][ty]
融合深搜思想的广搜(单方向扩展):
#include
#include
using namespace std;
#define inf 0x3fffffff //无穷大
#define M 105
int r, c, sx, sy, ex, ey, wan[M][M], t, k;//行数,列数,启动x,y终点x,y,弯数,测试数,拐弯数
char map[M][M];//接收控制台字符串
int x_move[4] = {-1, 0, 1, 0}; //四方向移动
int y_move[4] = {0, 1, 0, -1}; //四方向移动
struct pos{
int x, y;
};
void bfs ()
{
int i, j;
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
wan[i][j] = inf;
pos from, next;
from.x = sx, from.y = sy;//起点赋值
wan[from.x][from.y] = -1;
queue q;
q.push (from);
while (!q.empty())
{
from = q.front();
q.pop();
if (from.x == ex && from.y == ey && wan[from.x][from.y] <= k)
{
puts ("yes");
return ;
}
for (i = 0; i < 4; i++)
{
next.x = from.x + x_move[i];
next.y = from.y + y_move[i];
//whiile循环,单方向直走,该方向上所走过点的拐弯数均为wan[from.x][from.y]+1
while (!(next.x < 0 || next.y < 0 || next.x >= r || next.y >= c))
{
if (map[next.x][next.y] == '*')
break;
if (wan[next.x][next.y] < wan[from.x][from.y] + 1)//若下一步原来拐弯数比进入该步后(+1)的拐弯数小,说明已遍历过,并且是更优解,则无须再次遍历
break;
wan[next.x][next.y] = wan[from.x][from.y] + 1;//单方向扩展的每一步都相等,为wan[from.x][from.y]+1
if (wan[next.x][next.y] > k)//若拐弯数超了,跳出
break;
if (wan[next.x][next.y] == k && next.x != ex && next.y != ey)//若拐弯数达到最大,仍与终点不在一条直线上,则跳出
break;
q.push (next);
next.x += x_move[i];
next.y += y_move[i]; //单方向优先扩展
}
}
}
puts ("no");
}
int main()
{
int t, i;
scanf ("%d", &t);
while (t--)
{
scanf ("%d%d", &r, &c);
for (i = 0; i < r; i++)
scanf ("%s", map[i]);
scanf ("%d%d%d%d%d", &k, &sy, &sx, &ey, &ex);//到此,结束一趟控制台数据
sx--, sy--, ex--, ey--; //我从0开始编号,而题目是从1开始
bfs ();
}
return 0;
}
JAVA版广搜:
import java.util.Queue;
import java.util.Scanner;
import java.util.concurrent.LinkedBlockingDeque;
public class Main {
public static void main(String[] args) {
new Do().go();
}
}
class Do {
Queue que = new LinkedBlockingDeque();
Point start = new Point(), end = new Point();;
int[][] map = new int[103][103];
int[][] move = { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 } };
int high, len, sumTurn;
public void go() {
Scanner cin = new Scanner(System.in);
int n = 0;
n = cin.nextInt();
while (n-- > 0) {
high = cin.nextInt();
len = cin.nextInt();
for (int i = 1; i <= high; i++) {
char[] temp = cin.next().toCharArray();
for (int j = 1; j <= len; j++) {
if (temp[j - 1] == '.')
map[i][j] = Integer.MAX_VALUE;// 每个点拐弯数默认为0
else
map[i][j] = -1;// 障碍
}
}
sumTurn = cin.nextInt();
start.y = cin.nextInt();
start.x = cin.nextInt();
map[start.x][start.y] = -1;// 起点拐弯数-1,方便后面当走到下一步时+1,变成正常的初始0转弯数了。
end.y = cin.nextInt();
end.x = cin.nextInt();
// 将迷宫四周围成墙
for (int i = 0; i <= len + 1; i++) {
map[0][i] = -1;
map[high + 1][i] = -1;
}
for (int i = 0; i <= high; i++) {
map[i][0] = -1;
map[i][len + 1] = -1;
}
bfs();//广搜
}
}
private void bfs() {
if (!que.isEmpty())
que.clear();
que.offer(start);
while (!que.isEmpty()) {
Point from = que.poll();
if (from.x == end.x && from.y == end.y && map[from.x][from.y] <= sumTurn) {
System.out.println("yes");
return;
}
for (int i = 0; i < 4; i++) {
int nextTurn = map[from.x][from.y] + 1;
if (nextTurn > sumTurn)// 目标该点新转弯数超范围则退出对from结点的四方向遍历
break;
Point to = new Point();// 保存每一次走过的新结点
to.x = from.x + move[i][0]; // 单方向扩展,直走
to.y = from.y + move[i][1];
while (map[to.x][to.y] != -1) {
if (nextTurn > map[to.x][to.y])// 若目标结点的新转外数不如保存过的拐弯数则遍历下一方向
break;
if (nextTurn == sumTurn && to.x != end.x && to.y != end.y)
break;// 若目标结点拐弯数达到最大仍与终点不在一条直线
map[to.x][to.y] = nextTurn;// 若拐弯数小于原来的,则赋值
que.offer(to);
// 单方向扩展,直走
Point temp = to;
to = new Point();
to.x = temp.x + move[i][0];
to.y = temp.y + move[i][1];
}
}
}
System.out.println("no");
}
private class Point {
int x;
int y;
}
}