Problem Description
给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位置,只能走到与它相邻的4个位置中,当然在行走过程中,gloria不能走到迷宫外面去。令人头痛的是,gloria是个没什么方向感的人,因此,她在行走过程中,不能转太多弯了,否则她会晕倒的。我们假定给定的两个位置都是空地,初始时,gloria所面向的方向未定,她可以选择4个方向的任何一个出发,而不算成一次转弯。gloria能从一个位置走到另外一个位置吗?
Input
第1行为一个整数t (1 ≤ t ≤ 100),表示测试数据的个数,接下来为t组测试数据,每组测试数据中,
第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x 1, y 1, x 2, y 2 (1 ≤ k ≤ 10, 1 ≤ x 1, x 2 ≤ n, 1 ≤ y 1, y 2 ≤ m),其中k表示gloria最多能转的弯数,(x 1, y 1), (x 2, y 2)表示两个位置,其中x 1,x 2对应列,y 1, y 2对应行。
第1行为两个整数m, n (1 ≤ m, n ≤ 100),分别表示迷宫的行数和列数,接下来m行,每行包括n个字符,其中字符'.'表示该位置为空地,字符'*'表示该位置为障碍,输入数据中只有这两种字符,每组测试数据的最后一行为5个整数k, x 1, y 1, x 2, y 2 (1 ≤ k ≤ 10, 1 ≤ x 1, x 2 ≤ n, 1 ≤ y 1, y 2 ≤ m),其中k表示gloria最多能转的弯数,(x 1, y 1), (x 2, y 2)表示两个位置,其中x 1,x 2对应列,y 1, y 2对应行。
Output
每组测试数据对应为一行,若gloria能从一个位置走到另外一个位置,输出“yes”,否则输出“no”。
Sample Input
2 5 5 ...** *.**. ..... ..... *.... 1 1 1 1 3 5 5 ...** *.**. ..... ..... *.... 2 1 1 1 3
Sample Output
no yes
这道题的意思就是给定一个地图,“.”表示可以通过,“*”表示不能通过,然后给定一个出发点和一个终点,以及这个人所能转的最多次数,让你判断是否有可行的方法从出发点到终点,且转弯次数不超过k
这道题用dfs求解,中点在于终止搜索的条件,剪枝防止超时
参考:
https://blog.csdn.net/u013068502/article/details/38795113
代码:
//
// main.cpp
// 1728
//
// Created by showlo on 2018/5/16.
// Copyright © 2018年 showlo. All rights reserved.
//
#include <iostream>
#include <cstdio>
#include <cstring>
#define max 9999
using namespace std;
int n,m;
int k,x1,y1,x2,y2,flag;
char mp[120][120],vis[120][120];
int mark[120][120];//记录转弯次数
int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};
void dfs(int x,int y,int dire) //dire表示当前的方向,用于判断是否转弯
{
//终止条件
if(mark[x][y]>k)return; //转弯次数超过k,直接返回
if(x==x2&&y==y2&&mark[x][y]<=k)
{
flag=1; //如果到达目的点,同时此时的转弯次数不超过k,fl返回
return;
}
if(mark[x][y]==k&&x!=x2&&y!=y2)
return; //如果(x,y)和终点(x2,y2),既不在同一行也不在同一列,但是转弯次数已经达到最大,返回
if(flag)
return; //如果已经有满足的了,返回
//四个方向
for(int i=0; i<4; i++)
{
int nx=x+dir[i][0];
int ny=y+dir[i][1];
if(nx<0||ny<0||nx>=n||ny>=m||mp[nx][ny]=='*')
continue; //超出范围,返回
if(mark[nx][ny]<mark[x][y]) //剪枝,不能通过或者之前走过这里的步数比这次小
continue;
if(dire!=-1&&i!=dire&&mark[nx][ny]<mark[x][y]+1)//如果转弯了并且加上这一次转弯之后的转弯次数比之前的大,就换个方向
continue;
mark[nx][ny]=mark[x][y]; //记录转弯次数
if(dire!=-1&&i!=dire)
mark[nx][ny]++; //如果转弯了,就加1
mp[nx][ny]='*';
dfs(nx,ny,i);
mp[nx][ny]='.';//继续搜索,此时方向为i
if(flag) //如果找到了,返回
return;
}
}
int main()
{
int N;
cin>>N;
while(N--)
{
cin>>n>>m;
flag=0;
for(int i=0; i<n; i++)
cin>>mp[i];
cin>>k>>y1>>x1>>y2>>x2;
memset(mark,max,sizeof mark); //mark初始化为max
x1--;
x2--;
y1--;
y2--; //求出初始位置
mark[x1][y1]=0;
dfs(x1,y1,-1);
if(flag)
printf("yes\n");
else
printf("no\n");
}
return 0;
}