• HDU 1254 条件过程复杂的寻找最短路


    这里一看就是找箱子到终点的最短路

    一开始还傻傻的以为人的位置给的很没有意思- -,然后果然错了

    没过多久想明白了错误,因为你推箱子并不是你想去哪里推就能去哪推的,首先得考虑人能否过的去,因为可能人被箱子或墙挡住都是可能的

    虽然想明白了,但还是写了好久改了好久~~代码能力还是太渣了

    利用dfs判定人能否走到所在的位置,bfs搜最短路

    dp[i][j][4] 表示在第(i , j)位置上可以用4个方向推箱子,所以又得乘4种状态,最后就不断bfs计算这个dp值就好了

    要细心加上耐心哦~~

      1 /*我在这里假设箱子到了终点,我不断将它往回推,看能够推到的地方以及最短步数*/
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <iostream>
      5 #include <queue>
      6 using namespace std;
      7 int dir[4][2] = {{1 , 0} , {0 , 1} , {-1 , 0} , {0 , -1}};
      8 int m , n , dp[9][9][5] , a[9][9] , vis[9][9][5];
      9 int can[9][9]; //表示人能否到达那个位置
     10 
     11 struct Node{
     12     int x , y , pos; //pos表示人的位置,0,1,2,3表示4个方向
     13     Node(int x = 0 , int y = 0 , int pos = 0):x(x),y(y),pos(pos){}
     14 };
     15 
     16 queue<Node> q;
     17 //判断箱子从x , y按第 i 种方向推能否成立
     18 bool ok(int x , int y , int i)
     19 {
     20     int x1 = x+dir[i][0];
     21     int y1 = y+dir[i][1];
     22     int x2 = x-dir[i][0];
     23     int y2 = y-dir[i][1];
     24     if(x1<1 || x1>m || y1<1 || y1>n || x2<1 || x2>m || y2<1 || y2>n)
     25         return false;
     26     if(a[x1][y1] == 1 || a[x2][y2] == 1) return false;
     27     return true;
     28 }
     29 //用dfs搜索人所能走到的位置
     30 void dfs(int x , int y)
     31 {
     32     can[x][y] = 1;
     33     for(int i = 0 ; i<4 ; i++){
     34         int tx = x+dir[i][0];
     35         int ty = y+dir[i][1];
     36         if(tx>=1 && tx<=m && ty>=1 && ty<=n)
     37             if(a[tx][ty]!=1 && !can[tx][ty]) dfs(tx , ty);
     38     }
     39 }
     40 /*判断人从x1,y1 到x2 , y2这个位置在有箱子位于xbox , ybox遮挡的情况下能否到达*/
     41 bool canTo(int x1 , int y1 , int x2 , int y2 , int xbox , int ybox)
     42 {
     43     int tmp = a[xbox][ybox];
     44     a[xbox][ybox] = 1;//暂时将箱子所在位置变成墙
     45 
     46     memset(can , 0 , sizeof(can));
     47     dfs(x1 , y1);
     48 
     49     a[xbox][ybox] = tmp;//还原
     50     if(can[x2][y2] == 1) return true;
     51     return false;
     52 }
     53 
     54 void bfs(int sx , int sy , int pos)
     55 {
     56     dp[sx][sy][pos] = 0;
     57     q.push(Node(sx , sy , pos));
     58     while(!q.empty()){
     59         Node u = q.front();
     60         q.pop();
     61         vis[u.x][u.y][u.pos] = 0;
     62         for(int i = 0 ; i<4 ; i++){
     63             //人当前的位置
     64             int curx = u.x + dir[u.pos][0];
     65             int cury = u.y + dir[u.pos][1];
     66             //人将要走到的位置
     67             int nextx = u.x - dir[i][0];
     68             int nexty = u.y - dir[i][1];
     69             //先判定人即将到达的方向是否合理
     70             if(nextx < 1 || nextx > m || nexty < 1 || nexty>n) continue;
     71             //再判定人能否到达推箱子所在的位置
     72             if(!canTo(curx , cury , nextx , nexty , u.x , u.y)) continue;
     73 
     74             //如果箱子可以移动,那就记录移动时人所在的方向p
     75             int p = (i+2) % 4; //人是在箱子的反方向,这里可以这样用是因为dir中的方向设置的对称
     76             Node v = Node(u.x+dir[i][0] , u.y+dir[i][1] , p);
     77 
     78             if(ok(u.x , u.y , i)){
     79                // cout<<"pos: "<<v.x<<" "<<v.y<<" "<<dp[v.x][v.y]<<endl;
     80                 if(dp[v.x][v.y][v.pos] > dp[u.x][u.y][u.pos] + 1){
     81                     dp[v.x][v.y][v.pos] = dp[u.x][u.y][u.pos] + 1;
     82                     if(!vis[v.x][v.y][v.pos]){
     83                         vis[v.x][v.y][v.pos] = 1;
     84                         q.push(v);
     85                     }
     86                 }
     87             }
     88         }
     89     }
     90 }
     91 
     92 int main()
     93 {
     94   //  freopen("a.in" , "r" , stdin);
     95     int T;
     96     scanf("%d" , &T);
     97     while (T--){
     98         scanf("%d%d" , &m , &n);
     99         Node tmp1 , tmp2 , tmp3; //用来记录终点的位置,和箱子的位置和人的位置
    100         for(int i = 1 ; i<=m ; i++)
    101             for(int j = 1 ; j<=n ; j++){
    102                 scanf("%d" , &a[i][j]);
    103                 if(a[i][j] == 3) tmp1 = Node(i , j , 0);
    104                 if(a[i][j] == 2) tmp2 = Node(i , j , 0);
    105                 if(a[i][j] == 4) tmp3 = Node(i , j , 0);
    106             }
    107 
    108         memset(dp , 0x3f , sizeof(dp));
    109         memset(vis , 0 , sizeof(vis));
    110 
    111         memset(can , 0 , sizeof(can));
    112         a[tmp2.x][tmp2.y] = 1;
    113         dfs(tmp3.x , tmp3.y);
    114         a[tmp2.x][tmp2.y] = 2;
    115         //看最开始人能从哪个位置开始推
    116         for(int i = 0 ; i<4 ; i++){
    117             int tx = tmp2.x + dir[i][0];
    118             int ty = tmp2.y + dir[i][1];
    119             if(tx >= 1 && tx <= m && ty >= 1 && ty <= n)
    120                 if(can[tx][ty]){
    121                    // cout<<"haha: "<<tx<<"  " <<ty <<" "<<i<<endl;
    122                     bfs(tmp2.x , tmp2.y , i);
    123                 }
    124         }
    125 
    126         int minn = 0x3f3f3f3f;
    127         for(int i = 0 ; i<4 ; i++){
    128             minn = min(minn , dp[tmp1.x][tmp1.y][i]);
    129         }
    130         if(minn < 0x3f3f3f3f) printf("%d
    " , minn);
    131         else printf("-1
    ");
    132     }
    133     return 0;
    134 }
  • 相关阅读:
    Java 语义网编程系列二: 本体
    Java 语义网编程系列三: 现实世界中的知识建模
    Windows编程--线程和内核对象的同步-等待定时器内核对象
    Windows编程--虚拟内存的使用
    Windows编程--线程和内核对象的同步-事件内核对象
    Python 中文问题
    Windows编程--线程和内核对象的同步-信标(信号量)内核对象
    Windows编程--伪句柄
    Windows编程-- 线程和内核对象的同步 - 互斥对象内核对象
    Windows编程-- Windows的内存结构
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4184982.html
Copyright © 2020-2023  润新知