题目链接: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. NYOJ92 图像实用区域 【BFS】

    碰到了一个曾经从未见过的奇怪问题:先上截图: 执行号 用户 题目 结果 时间 内存 语言 提交时间 895360 userid=%E9%95%BF%E6%9C%A8" style=" ...

  2. day06_方法_20150806

    day06_方法_20150806 -------------------------回想:--------------------------------- 1.更佳适用情况       当---w ...

  3. Python获取免费的可用代理

    Python获取免费的可用代理 在使用爬虫多次爬取同一站点时,常常会被站点的ip反爬虫机制给禁掉,这时就能够通过使用代理来解决.眼下网上有非常多提供最新免费代理列表的站点.这些列表里非常多的代理主机是 ...

  4. Spring2.5学习3.2_编码剖析@Resource注解的实现原理

    首先看一下J2EE提供的@Resource注解:该注解默认安照名称进行装配,名称能够通过name属性进行指定, 假设没有指定name属性,当注解写在字段上时,默认取字段名进行依照名称查找,假设注解写在 ...

  5. 转:几款主流pcb软件比较

      原理图设计软件:会ORCAD就可以了,支持的Netlist超多,基本是业界标准. PCB Layout 软件 1.Protel,现在推AltiumDesigner.国内低端设计的主流,国外基本没人 ...

  6. MySQL的安装过程

     近期对MySQL做了一些研究. 曾经主要接触的是SQL SERVER.所以,今天对该安装过程做了一些总结以及使用过程中的一些心得.并分享给大家. 记得前面.分享过一篇关于数据库的几种连接方式.而 ...

  7. Python操作Execl 实现自动化填表

    任务简述: 表1是一个简单的数据表,共有110行,25列.第1行是表头,例如“负责人”.“事项”.“期限”等. 第2行——第110行是对应的数据,如“张三”.“搬砖头”.“3天”. 想要做的表(表2) ...

  8. c# .net 关于接口实现方式:隐式实现/显式实现!

    以前在用到接口时,从来没注意到接口分为隐式实现与显示实现.昨天在浏览博客时看到相关内容,现在根据自己的理解记录一下,方便日后碰到的时候温习温习.  通俗的来讲,“显示接口实现”就是使用接口名称作为方法 ...

  9. 华为P20无敌拍摄能力开放 如何即刻获得?

    在全球专业相机测评机构DXOmark发布的相机评测排行中,华为P20.P20 Pro成功登顶“全球拍照最好智能手机”.P20 Pro综合得分高达109分,P20综合得分102分.“华为并非简单地将第三 ...

  10. Koa2+MySQL+VUE+ElementIUI搭建简单的后台管理小系统

    如题,前端入坑许久,还是写个小东西出来吧 想要搭建自己的一个后台管理,实现简单的增删改查,看起来很简单 其实是真的简单,没有想的那么难,我也就写了一个月吧, 当然是假的,其实也就每天一两个小时,花了大 ...