zoukankan      html  css  js  c++  java
  • hdu 1728 DFS+剪枝 逃离迷宫

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 typedef struct Node
      6 {
      7     int x, y;
      8 }Node;
      9 
     10 const int MAX = 10000;
     11 const int N = 110;
     12 const int dir[4][2] = { {-1,0}, {0,1}, {1,0}, {0,-1} };//移动方向
     13 bool visit[N][N];        //标记数组
     14 char board[N][N];        //棋盘
     15 int turn[N][N];          //turn数组用于记录棋盘上各点已知的最少的转弯次数
     16 Node origin, destination;//起点、终点
     17 int maxTurnCount;        //路痴所能承受的最大转弯次数
     18 int m, n;                //棋盘的行、列
     19 
     20 
     21 inline bool inBoard(const int &row, const int &col)
     22 {
     23     return 0 <= row && row < m && 0 <= col && col < n;
     24 }
     25 
     26 /* dfs搜索(参数含义:行、列、上一次移动的方向) */
     27 bool dfs(const int &row, const int &col, int direction)
     28 {
     29     //在路痴可以承受的转向次数内到达终点
     30     if (row == destination.x && col == destination.y && turn[row][col] <= maxTurnCount)
     31         return true;
     32 
     33     //转向的次数超过路痴所能承受的次数,路痴已经晕了,因此不可取
     34     if (turn[row][col] > maxTurnCount)
     35         return false;
     36 
     37     //路痴的位置与终点不在同一行同一列,那么至少需要再转向一次,但是当前的转向次数已经等于路痴所能承受的最大转弯次数
     38     if (row != destination.x && col != destination.y && turn[row][col] == maxTurnCount)
     39         return false;
     40 
     41     for (int i = 0; i < 4; ++i)
     42     {
     43         int r = row + dir[i][0];
     44         int c = col + dir[i][1];
     45         if (true == inBoard(r, c) && '.' == board[r][c] && false == visit[r][c])
     46         {
     47             /* turn[r][c]记录的是历史上走到(r,c)所用的最短的转弯次数,turn[r][c]的初始值MAX */
     48             /* 剪枝1:从(row, col)位置走向(r, c)位置,如果turn[r][c] < turn[row][col],说明之前
     49             路痴已经走到过这里了,并且上次的转弯次数比这次小,上次都没走到终点,这次更加走不到。
     50             相等的情况不能剪掉,举个栗子:从起点(1, 1),走向终点(3, 5),一种方法是向右走,一种方法
     51             是向下走。向右走的时候,走到(3, 4)的时候,转弯次数是1,那么turn[3][4] = 1,在转一次
     52             才走到,那么需要转两次;向下走的时候,又走到(3, 4),转弯次数也是1,由于之前走到过,
     53             然而两次转弯次数相同,后一种情况(走到终点只需要转弯一次)被剪枝剪掉了,如果题目给
     54             出的最大转弯次数是1,那么就得不到正确答案了。
     55             ....*
     56             .**.*
     57             .....
     58             */
     59             if (turn[r][c] < turn[row][col])
     60                 continue;
     61 
     62             /* 剪枝2:跟剪枝1的原理类似,从(row, col)走向(r, c),由于方向改变了,因此转弯次数
     63             需要加一,转弯次数加一后如果比(r, c)历史上的转弯次数还多,就需要把这种情况给剪掉。
     64             相等的情况不能剪掉 */
     65             if (-1 != direction && i != direction && turn[r][c] < turn[row][col] + 1)
     66                 continue;
     67 
     68             if (-1 != direction && i != direction)
     69                 turn[r][c] = turn[row][col] + 1;//移动方向与之前的不同,转弯次数+1
     70             else
     71                 turn[r][c] = turn[row][col];    //移动方向与之前的相同,转弯次数不变
     72 
     73             visit[r][c] = true;
     74 
     75             if (true == dfs(r, c, i)) return true;
     76 
     77             //回溯
     78             visit[r][c] = false;
     79         }
     80     }
     81     return false;
     82 }
     83 
     84 void input(void)
     85 {
     86     scanf("%d %d", &m, &n);     //输入行、列
     87     for (int i = 0; i < m; ++i) //输入棋盘
     88         scanf("%s", board[i]);
     89 
     90     //这里有坑:“5个整数k, x1, y1, x2, y2 (1 ≤ k ≤ 10, 1 ≤ x1, x2 ≤ n, 1 ≤ y1, y2 ≤ m)”
     91     //1 ≤ x1, x2 ≤ n  => x1,x2是列;1 ≤ y1, y2 ≤ m  => y1,y2是行
     92     //出题人挖的坑,不要被惯性思维束缚了
     93     scanf("%d %d %d %d %d", &maxTurnCount, &origin.y, &origin.x, &destination.y, &destination.x);
     94 
     95     //初始化数据
     96     for (int i = 0; i < m; ++i)
     97         for (int j = 0; j < n; ++j)
     98             turn[i][j] = MAX;
     99     memset(visit, 0, sizeof(visit));
    100     origin.y--; //题目给出的坐标从1开始,因此需要对坐标进行处理,让其从0开始
    101     origin.x--;
    102     destination.y--;
    103     destination.x--;
    104 }
    105 
    106 int main(void)
    107 {
    108     int t;//测试组数
    109     scanf("%d", &t);
    110     for (int k = 0; k < t; ++k)
    111     {
    112         input();
    113         visit[origin.x][origin.y] = true;
    114         turn[origin.x][origin.y] = 0;
    115         if (true == dfs(origin.x, origin.y, -1))
    116             printf("yes
    ");
    117         else
    118             printf("no
    ");
    119     }
    120     return 0;
    121 }
  • 相关阅读:
    Python开发之路
    openstack系列阅读目录
    linux基础
    PEP8规范
    我真的还是18岁的那个我
    为什么很多IT公司不喜欢进过培训机构的人呢?
    GRE与VXLAN
    VLAN模式
    网络虚拟化基础一:linux名称空间Namespaces
    四:OVS+GRE之网络节点
  • 原文地址:https://www.cnblogs.com/yongqiang/p/5693077.html
Copyright © 2011-2022 走看看