• RQNOJ 342 最不听话的机器人:网格dp


    题目链接:https://www.rqnoj.cn/problem/342

    题意:

      DD 有一个不太听话的机器人,这个机器人总是会有自己的想法,而不会完全遵守 DD 给它的指令。

      现在 DD 在试图命令机器人走迷宫。迷宫是一个 N*N 个格子组成的区域,格子自左上角到右下角从 (1,1) 到 (N,N) 编号。第 i 行、第 j 列的格子编号为 (i,j)。迷宫中的某些区域是障碍物,机器人不能移动到那里。

      DD 给了机器人 M 条指令,指令的类型包括“前进一步”“后退一步”“左转九十度”“右转九十度”。但问题是机器人并不能完全遵守这些指令,因为如果机器人完全遵守这些指令,它可能会走到障碍物的格子里或者走到迷宫外面去,那样就会有危险。机器人希望从这个指令序列里面去掉一些,然后执行剩下的指令时,可以保证整个过程中都不会有危险。

      机器人虽然不太听话,但它并不想惹恼了 DD,否则 DD 可能会把它拆掉的。所以机器人希望去掉的指令尽量少。

      迷宫的大小是 N*N,指令共有 M 条,机器人初始时的位置是 (X0,Y0)。机器人初始时面朝的方向是上方。

      那么,机器人最少需要去掉多少条指令才能保证不会有危险呢?

    题解:

      表示状态:

        dp[i][x][y][d] = min num of deleted orders

        i:考虑到第i条指令

        x,y:当前位置

        d:当前方向

      找出答案:

        min legal dp[m][x][y][d]

      如何转移:

        now: dp[i][x][y][d]

        dp[i+1][x][y][d] = min dp[i][x][y][d] + 1 (不执行)

        dp[i+1][nx][ny][nd] = min dp[i][x][y][d] (执行)

        nx,ny,nd为执行第i条指令后的位置和方向。

      边界条件:

        dp[0][x0][y0][UP] = 0

        ohters = INF

        (UP为方向向上的编号)

      注:空间限制,要把第一维[MAX_M]变为[2]。

     

      小技巧:

        如果压维的时候前后数据间有影响,则可以开一个vis数组。

        更新dp[i&1][x][y][d]时,将vis[i&1][x][y][d] = i,意为当前dp的位置是在i的时候更新的。

        每次用到dp[i&1][x][y][d]时,判断一下相应的vis。

        如果vis[i&1][x][y][d] = i,则返回dp值,否则返回初始值INF(dp[i][x][y][d]这个状态还没被更新过)。

    AC Code:

      1 // state expression:
      2 // dp[i][x][y][d] = min num of deleted orders
      3 // i: considering ith order
      4 // x,y: present pos
      5 // d: present direction
      6 //
      7 // find the answer:
      8 // min legal dp[m][x][y][d]
      9 //
     10 // transferring:
     11 // now: dp[i][x][y][d]
     12 // dp[i+1][x][y][d] = min dp[i][x][y][d] + 1
     13 // dp[i+1][nx][ny][nd] = min dp[i][x][y][d]
     14 //
     15 // bound:
     16 // dp[0][x0][y0][UP] = 0
     17 // ohters = INF
     18 #include <iostream>
     19 #include <stdio.h>
     20 #include <string.h>
     21 #define MAX_N 105
     22 #define MAX_M 1005
     23 #define MAX_D 5
     24 #define INF 10000000
     25 
     26 using namespace std;
     27 
     28 const int dx[]={-1,0,1,0};
     29 const int dy[]={0,1,0,-1};
     30 
     31 int n,m,x0,y0;
     32 int ans;
     33 int c[MAX_M];
     34 int dp[2][MAX_N][MAX_N][MAX_D];
     35 int vis[2][MAX_N][MAX_N][MAX_M];
     36 char a[MAX_N][MAX_N];
     37 
     38 void read()
     39 {
     40     cin>>n>>m>>x0>>y0;
     41     for(int i=1;i<=n;i++)
     42     {
     43         for(int j=1;j<=n;j++)
     44         {
     45             cin>>a[i][j];
     46         }
     47     }
     48     string s;
     49     for(int i=0;i<m;i++)
     50     {
     51         cin>>s;
     52         if(s=="FORWARD") c[i]=0;
     53         if(s=="BACK") c[i]=1;
     54         if(s=="LEFT") c[i]=2;
     55         if(s=="RIGHT") c[i]=3;
     56     }
     57 }
     58 
     59 void cal_pos(int &x,int &y,int &d,int c)
     60 {
     61     if(c==0)
     62     {
     63         x+=dx[d];
     64         y+=dy[d];
     65         return;
     66     }
     67     if(c==1)
     68     {
     69         x-=dx[d];
     70         y-=dy[d];
     71         return;
     72     }
     73     if(c==2)
     74     {
     75         d=(d+3)%4;
     76         return;
     77     }
     78     if(c==3)
     79     {
     80         d=(d+1)%4;
     81         return;
     82     }
     83 }
     84 
     85 inline bool is_legal(int x,int y)
     86 {
     87     return x>0 && x<=n && y>0 && y<=n && a[x][y]!='*';
     88 }
     89 
     90 void solve()
     91 {
     92     memset(dp,0x3f,sizeof(dp));
     93     memset(vis,-1,sizeof(vis));
     94     dp[0][x0][y0][0]=0;
     95     vis[0][x0][y0][0]=0;
     96     for(int i=0;i<m;i++)
     97     {
     98         for(int x=1;x<=n;x++)
     99         {
    100             for(int y=1;y<=n;y++)
    101             {
    102                 if(a[x][y]!='*')
    103                 {
    104                     for(int d=0;d<4;d++)
    105                     {
    106                         if(vis[i&1][x][y][d]==i)
    107                         {
    108                             int temp;
    109                             if(vis[(i+1)&1][x][y][d]!=i+1) temp=INF;
    110                             else temp=dp[(i+1)&1][x][y][d];
    111                             dp[(i+1)&1][x][y][d]=min(temp,dp[i&1][x][y][d]+1);
    112                             vis[(i+1)&1][x][y][d]=i+1;
    113                             int nx=x,ny=y,nd=d;
    114                             cal_pos(nx,ny,nd,c[i]);
    115                             if(is_legal(nx,ny))
    116                             {
    117                                 if(vis[(i+1)&1][nx][ny][nd]!=i+1) temp=INF;
    118                                 else temp=dp[(i+1)&1][nx][ny][nd];
    119                                 dp[(i+1)&1][nx][ny][nd]=min(temp,dp[i&1][x][y][d]);
    120                                 vis[(i+1)&1][nx][ny][nd]=i+1;
    121                             }
    122                         }
    123                     }
    124                 }
    125             }
    126         }
    127     }
    128     ans=m;
    129     for(int x=1;x<=n;x++)
    130     {
    131         for(int y=1;y<=n;y++)
    132         {
    133             if(a[x][y]!='*')
    134             {
    135                 for(int d=0;d<4;d++)
    136                 {
    137                     if(vis[m&1][x][y][d]==m)
    138                     {
    139                         ans=min(ans,dp[m&1][x][y][d]);
    140                     }
    141                 }
    142             }
    143         }
    144     }
    145 }
    146 
    147 void print()
    148 {
    149     cout<<ans<<endl;
    150 }
    151 
    152 int main()
    153 {
    154     read();
    155     solve();
    156     print();
    157 }
  • 相关阅读:
    JDK6的switch支持不是很好
    团队作业(2)
    团队作业(1)
    4月30日
    重构:改善既有代码的设计有感
    4月28日
    4月27日
    4月26日
    4月25日
    4月24日
  • 原文地址:https://www.cnblogs.com/Leohh/p/7461084.html
Copyright © 2020-2023  润新知