RQNOJ 342 最不聽話的機器人:網格dp

Leohh發表於2017-08-31

題目連結: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 }

 

相關文章