题目链接: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:

 // state expression:
// dp[i][x][y][d] = min num of deleted orders
// i: considering ith order
// x,y: present pos
// d: present direction
//
// find the answer:
// min legal dp[m][x][y][d]
//
// transferring:
// 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]
//
// bound:
// dp[0][x0][y0][UP] = 0
// ohters = INF
#include <iostream>
#include <stdio.h>
#include <string.h>
#define MAX_N 105
#define MAX_M 1005
#define MAX_D 5
#define INF 10000000 using namespace std; const int dx[]={-,,,};
const int dy[]={,,,-}; int n,m,x0,y0;
int ans;
int c[MAX_M];
int dp[][MAX_N][MAX_N][MAX_D];
int vis[][MAX_N][MAX_N][MAX_M];
char a[MAX_N][MAX_N]; void read()
{
cin>>n>>m>>x0>>y0;
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
cin>>a[i][j];
}
}
string s;
for(int i=;i<m;i++)
{
cin>>s;
if(s=="FORWARD") c[i]=;
if(s=="BACK") c[i]=;
if(s=="LEFT") c[i]=;
if(s=="RIGHT") c[i]=;
}
} void cal_pos(int &x,int &y,int &d,int c)
{
if(c==)
{
x+=dx[d];
y+=dy[d];
return;
}
if(c==)
{
x-=dx[d];
y-=dy[d];
return;
}
if(c==)
{
d=(d+)%;
return;
}
if(c==)
{
d=(d+)%;
return;
}
} inline bool is_legal(int x,int y)
{
return x> && x<=n && y> && y<=n && a[x][y]!='*';
} void solve()
{
memset(dp,0x3f,sizeof(dp));
memset(vis,-,sizeof(vis));
dp[][x0][y0][]=;
vis[][x0][y0][]=;
for(int i=;i<m;i++)
{
for(int x=;x<=n;x++)
{
for(int y=;y<=n;y++)
{
if(a[x][y]!='*')
{
for(int d=;d<;d++)
{
if(vis[i&][x][y][d]==i)
{
int temp;
if(vis[(i+)&][x][y][d]!=i+) temp=INF;
else temp=dp[(i+)&][x][y][d];
dp[(i+)&][x][y][d]=min(temp,dp[i&][x][y][d]+);
vis[(i+)&][x][y][d]=i+;
int nx=x,ny=y,nd=d;
cal_pos(nx,ny,nd,c[i]);
if(is_legal(nx,ny))
{
if(vis[(i+)&][nx][ny][nd]!=i+) temp=INF;
else temp=dp[(i+)&][nx][ny][nd];
dp[(i+)&][nx][ny][nd]=min(temp,dp[i&][x][y][d]);
vis[(i+)&][nx][ny][nd]=i+;
}
}
}
}
}
}
}
ans=m;
for(int x=;x<=n;x++)
{
for(int y=;y<=n;y++)
{
if(a[x][y]!='*')
{
for(int d=;d<;d++)
{
if(vis[m&][x][y][d]==m)
{
ans=min(ans,dp[m&][x][y][d]);
}
}
}
}
}
} void print()
{
cout<<ans<<endl;
} int main()
{
read();
solve();
print();
}

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

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

    题面 传送门:https://www.luogu.org/problemnew/show/P1006 Solution 挺显然但需要一定理解的网络(应该是那么叫吧)DP 首先有一个显然但重要的结论要发 ...

  2. rqnoj-342-最不听话的机器人-dp

    dp[i][j][k][[l]: 执行第i步,执行到点(j,k),方向为l时,用的最大步数. 状态转移根据step[i]转移. #include<stdio.h> #include< ...

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

    题目链接:https://www.rqnoj.cn/problem/311 题意: 给你一个长度为n的数字,用t个乘号分开,问你分开后乘积最大为多少.(6<=n<=40,1<=k&l ...

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

    题目链接:https://www.rqnoj.cn/problem/622 题意: 一个机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得. w[i][j]是从供应商j处购得的部件i的重量, ...

  5. 1088. [SCOI2005]扫雷Mine【网格DP】

    Description 相信大家都玩过扫雷的游戏.那是在一个n*m的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了 ,“余”人国流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子 ...

  6. 1084. [SCOI2005]最大子矩阵【网格DP】

    Description 这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大.注意:选出的k个子矩阵 不能相互重叠. Input 第一行为n,m,k(1≤n≤100,1≤m≤ ...

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

    题面 传送门:https://www.luogu.org/problemnew/show/P4147 Solution 裸的求极大子矩阵 感谢wzj dalao的教学 首先,有一个很显然但很重要的结论 ...

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

    唉 不想说什么了 poj 1703,从看完题到写完第一个版本的代码,只有15分钟 然后一直从晚上八点WA到第二天早上 最后终于发现了BUG,题目要求的“Not sure yet.”,我打成了“No s ...

  9. 五大常见算法策略之——动态规划策略(Dynamic Programming)

    Dynamic Programming   Dynamic Programming是五大常用算法策略之一,简称DP,译作中文是"动态规划",可就是这个听起来高大上的翻译坑苦了无数人 ...

随机推荐

  1. 实战c++中的vector系列--vector的遍历(stl算法、vector迭代器(不要在循环中推断不等于end())、operator[])

    遍历一个vector容器有非常多种方法.使用起来也是仁者见仁. 通过索引遍历: for (i = 0; i<v.size(); i++) { cout << v[i] << ...

  2. TP5结合聚合数据API查询天气

    php根据城市查询天气情况看到有人分享java的查询全国天气情况的代码,于是我想分享一个php版本的查询天气接口.免费查询天气的接口有很多,比如百度的apistore的天气api接口,我本来想采用这个 ...

  3. Android Touch事件传递机制具体解释 下

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38025165 资源下载:http://download.csdn.net/detail/yu ...

  4. ORA-02050故障诊断一例

    http://czmmiao.iteye.com/blog/1474678昨天客户反映说在下午某时间段有几个事务失败了,让我查下当时数据库系统的负载是否正常,看了下CPU的历史负载,很正常,于是看了下 ...

  5. BZOJ 1293 SCOI2009 生日礼物 堆

    题目大意:给定一个数轴上n个点,每一个点有一种颜色,一共k种颜色.求一个最短的区间,包括全部k种颜色 卡了一段时间0.0 一開始想二分答案啥的 后来发现数据范围太大写不了0.0 后来去找题解才发现尼玛 ...

  6. CPU核心电压与VID电压

    1.CPU核心电压与VID电压的区别 VID是CPU电压识别信号,CPU的工作电压就是由VID来定义的,CPU核心电压是CPU正常工作所需的电压 原理: (1)通常主板上用硬件VID确定BOOT VI ...

  7. 26:IPMaskCheck识别有效的ip地址和掩码并分类统计

    题目描述 请解析IP地址和对应的掩码,进行分类识别.要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类. 所有的IP地址划分为 A,B,C,D,E五类 A类地址1.0.0.0~126.2 ...

  8. modelsim-altera IP核仿真

    modelsim 仿真fifo时出现 Instantiation of 'scfifo' failed. The design unit was not found. 2012-07-21 13:27 ...

  9. Office 365 开发入门

    <Office 365 开发入门指南>公开邀请试读,欢迎反馈 终于等来了这一天,可以为我的这本新书画上一个句号.我记得是在今年的2月份从西雅图回来之后,就萌发了要为中国的Office 36 ...

  10. 20-ab压力测试及nginx性能统计模块

    一:找到apache ab模块. ab -c 1000 -n 50000 http://127.0.0.1/index.html 查看信息: 超过1024个线程 出现错误,说打开文件太多了.cket: ...