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 }
时间: 2024-10-11 16:11:17

RQNOJ 342 最不听话的机器人:网格dp的相关文章

[Luogu P1006]传纸条 (网格DP)

题面 传送门:https://www.luogu.org/problemnew/show/P1006 Solution 挺显然但需要一定理解的网络(应该是那么叫吧)DP 首先有一个显然但重要的结论要发现:从左上走到右下再从右下走回左上=从左上走两次到右下 那么接下来可以考虑: 设f[i][j][k][l]为第一次走到了(i,j)第二次走到了(k,l) 在路径不交错为前提下的能取到的最大友好值 转移方程也挺好写的 考虑这种情况能从哪里转移过来就好(i,j)可以从(i-1,j)或(i,j-1)转移过

动态规划解决机器人网格路径问题!

想获得更好的排版,请移步个人博客: https://pushy.site 无障碍物 题目(原题见 LeetCode - 62. 不同路径):一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ).机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为"Finish").问总共有多少条不同的路径? 示例 1: 输入: m = 3, n = 2 输出: 3 解释: 从左上角开始,总共有 3 条路径可以到达右下角.

RQNOJ 622 最小重量机器设计问题:dp

题目链接:https://www.rqnoj.cn/problem/622 题意: 一个机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得. w[i][j]是从供应商j处购得的部件i的重量,c[i][j] 是相应的价格. 试设计一个算法,给出总价格不超过d的最小重量机器设计. 题解: 表示状态: dp[i][j] = min weight i:考虑到第i个零件 j:当前花费 找出答案: min dp[n][j] (0<=j<=d) 如何转移: 对于当前零件i,枚举不同的供应商j,转移

RQNOJ 311 [NOIP2000]乘积最大:划分型dp

题目链接:https://www.rqnoj.cn/problem/311 题意: 给你一个长度为n的数字,用t个乘号分开,问你分开后乘积最大为多少.(6<=n<=40,1<=k<=30) 题解: 简化问题: 给原数字之前添加一个"1 *",乘号不计入数量,对答案无影响. 例如:"1231"可以变成"(1*)1231". 表示状态: dp[i][j] = max num(最后一个乘号之前的最大乘积) i:此时在第i个数的前

[Luogu P4147] 玉蟾宫 (网格DP)

题面 传送门:https://www.luogu.org/problemnew/show/P4147 Solution 裸的求极大子矩阵 感谢wzj dalao的教学 首先,有一个很显然但很重要的结论,那就是求极大子矩阵肯定要贴着边或一个障碍点,否则就会浪费 根据这个定理,我们可以考虑一种做法 我们可以枚举每一个可放置的点 我们可以很轻松的得知它与它左边的障碍点(或边界)的距离,也可以得知它上面与下面能扩展到哪里(即无障碍点最多能到哪里) 那这个点能扩出的长方形的最大面积就是它左边的上面与下面能

【原创】POJ 1703 &amp;&amp; RQNOJ 能量项链解题报告

唉 不想说什么了 poj 1703,从看完题到写完第一个版本的代码,只有15分钟 然后一直从晚上八点WA到第二天早上 最后终于发现了BUG,题目要求的“Not sure yet.”,我打成了“No sure yet.” 然后是RQNOJ的NOIP真题,经典的能量项链 从看完题到写完伪码用了30分钟,敲完全部代码用了10分钟 WA 了7次,次次只能过前三个点,后面全部超时. 不能够啊?我动态规划了都,怎么可能超时? 开始优化主函数. 发现通过一个比较,能把N * (N-1)的复杂度降到C(N,2)

Scratch 少儿编程网

少儿编程网  http://www.shaoerbianchengwang.com/scratch <Scratch游戏制作教程>资料http://www.shaoerbianchengwang.com/tag/scratch%E6%B8%B8%E6%88%8F%E5%88%B6%E4%BD%9C[scratch游戏制作案例及教程]猫狗大战(抓小偷)[scratch游戏制作案例及教程]植物大战僵尸(口算篇) [scratch游戏制作案例及教程]黄金矿工(挖宝藏) [scratch游戏制作案例及

UVA-11795 (状压dp)

题意: 按照一定的顺序消灭n个机器人,每消灭一个机器人就可得到它的武器,每个机器人只有用特定的武器才能消灭,现在给定一个初始的武器,它能消灭一些机器人,每个机器人的武器能消灭那些机器人也给你了,现在要你求消灭n个机器人的顺序总数; 思路: dp[i][k]表示在第i次操作时的用k表示已经挂掉的机器人的操作顺序数; 枚举第i次要攻击的机器人j;dp[i][x]+=dp[i-1][k];x是挂到j后k与j表示的状态; AC代码: /**********************************

HDU 4003 Find Metal Mineral (树形DP,树形分组背包,经典)

题意:给定一棵树图,n个节点,有边权,要派k<11个机器人从节点s出发,遍历所有的点,每当1只机器人经过1条边时就会花费该边的边权,边是可重复走的.问遍历完所有点的最小花费? 思路: 非常经典,首先需要知道一点,才能往下推理.就是“如果在t点派c个机器人往孩子u,那么最多只有1个机器人能走会回来到t,否则花费总是不划算的”. 稍微证明一下: (1)假设派1个机器人往u,逛一圈回到u的父亲t,花费v= 子树u的边权和*2 + e(t,u)*2.若机器人不要了,那花费肯定比v还要少. (2)假设派2