题目链接: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. 红米note3刷安卓原生

    http://www.romzj.com/rom/63404.htm#comments-version 然后在系统设置里升级系统, http://www.lineageosdownloads.com/ ...

  2. Node.js学习笔记(3)——关于回调函数和函数的回调

    说明:本人是node.js的初学者,尝试向别人解释这是怎么回事是自我学习的一个好方法.如果你发现有些地方并不是那么正确,欢迎提出来让我知道以便修正,共同进步,谢过^_^.       欢迎交流,本人微 ...

  3. LeetCode Hash Table 3. Longest Substring Without Repeating Characters

    HashMap的应用可以提高查找的速度,键key,值value的使用拜托了传统数组的遍历查找方式,对于判断一个字符或者字符串是否已经存在的问题可以非常好的解决.而本题需要解决的问题就是判断新遍历到的字 ...

  4. [Java开发之路](23)装箱与拆箱

    1. 简单介绍 大家对基本数据类型都很熟悉.比如 int.float.double.boolean.char 等.基本数据类型是不具备对象的特性,比方基本类型不能调用方法.功能简单. ..,为了让基本 ...

  5. Linux 查看.so中导出函数

    方法一 nm -D  **.so 但这样能看到所有的导出,乱七八糟的很多,筛选用: nm **.so | grep XX 方法二objdump -tT **.so

  6. oracle查询数据库资源位置

    archival log list; 归档日志文件位置 select file_name from dba_data_files; 查询数据库文件位置 select parameter control ...

  7. linux crontab 定时任务解析

    -----------crontab定时任务---------------------- 检查crontab工具是否安装 crontab -l 检查crontab服务是否启动 service cron ...

  8. python编程基础:《http://www.cnblogs.com/wiki-royzhang/category/466416.html》

    windows自动化 http://www.cnblogs.com/wiki-royzhang/category/466416.html

  9. 九度OJ 1047:素数判定 (素数)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:9583 解决:4347 题目描述: 给定一个数n,要求判断其是否为素数(0,1,负数都是非素数). 输入: 测试数据有多组,每组输入一个数n ...

  10. wimdows安装mongodb,开机启动

    > d: > cd D:\Program Files\MongoDB\Server\3.0\bin > .\mongod --logpath "D:\Program Fil ...