【HDU】1728 逃离迷宫(C++/C)

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对应行。
 

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;
}

猜你喜欢

转载自blog.csdn.net/biongbiongdou/article/details/80350616