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 }

 

posted @ 2017-08-31 23:24  Leohh  阅读(263)  评论(0编辑  收藏  举报