[NOIP2013 提高组] 华容道 P1979 洛谷
[NOIP2013 提高组] 华容道 P1979 洛谷
强烈推荐,更好的阅读体验
经典题目:spfa+bfs+转化
题目大意:
给出一个01网格图,和点坐标x,y空格坐标a,b,目标位置tx,ty要求移动空格最少步数使点到tx,ty
本题关键:
我们可以发现本题可以用BFS获得很高的暴力分,但是也可以使用DP:
但是本题的多次询问给我们一个启发-->可以预处理
所有我们可能可以预先处理一些状态的转移
可以发现很多状态是无效的,对于一个正确的移动路径:一定由两个部分组成
1.空格移动到目标格附近-->2.目标格借助空格移动到终点
对于前者很容易独立求出,对于后者,我们单独优化
目标点与空格的位置合并为一个状态,容易发现这个状态是4维的,空间卡住,时间__了

优化状态:
$f[i][j][0/1/2/3]表示目标点x=i,y=j,空格在其上下左右的相邻位置的状态$
为什么可以这样定义:因为在目标格借助空格移动到终点的过程中
假设目标点是下图黄球,空格只能是蓝球不能是绿球

不需要怎么了
状态之间的联系:
相邻状态:黄球位置确定下的所有蓝球位置(有效<=4)
所有对于一个状态考虑的转移左右3+1个
另外一个是空格目标交换位置(下图两种情况)
下面就可以上代码了
1 //先看主函数
2 #include<bits/stdc++.h>
3 #define ll int
4 #define f(i,a,b) for(ll i=a;i<=b;i++)
5 #define fd(i,a,b) for(ll i=a;i>=b;i--)
6 #define il inline
7 #define gc getchar()
8 #define r(i,a) for(ll i=fir[a];i;i=e[i].nex)
9 const ll maxn=32,INF=1e9,half=10,maxm=1e5;
10 ll n,m,q;
11 using namespace std;
12 bool Map[maxn][maxn];
13 ll xa[10]={-1,0,1, 0,0,0,0};
14 ll ya[10]={0, 1,0,-1,0,0,0};
15 //下 左→ ←
16 ll f[maxn][maxn][half],cnt;
17 ll dis[maxn][maxn],fir[maxm];
18 //把所有数组定义提前,以免重复或re
19 struct edge{ll to,nex,w;}e[maxm<<1];
20
21 il void add(ll a,ll b,ll c){e[++cnt].to=b,e[cnt].nex=fir[a],e[cnt].w=c;fir[a]=cnt;}
22
23 //↑用于spfa的建边,在dfs中建边
24 ll getnum(ll x,ll y){return ((x-1)*(m)+y)<<2;}
25 //对于每个空格与目标个相邻的状态进行编号
26 ll fat(ll x){return (x+2)%4;}
27 //空格相对于目标格的位置下上右左-->上下左→
28 queue<pair<ll,ll> >que;
29 //记录空格在s的d方位
30 il void bfs(ll a,ll b,ll x,ll y,ll d){//重复使用bfs
31 //a,b是枚举格子,x,y是空格
32 memset(dis,-1,sizeof(dis));
33 dis[a][b]=1;//防止被加入队列
34 dis[x][y]=0;
35 que.push(make_pair(x,y));
36 while(!que.empty()){
37 ll ux=que.front().first,uy=que.front().second;
38 que.pop();
39 f(i,0,3){
40 ll vx=ux+xa[i],vy=uy+ya[i];
41 if(Map[vx][vy]&&dis[vx][vy]==-1){
42 que.push(make_pair(vx,vy));
43 dis[vx][vy]=dis[ux][uy]+1;
44 }
45 }
46 }
47 if(d==5) return;//用于每次处理最少空格单独行走步数
48 ll num=getnum(a,b);
49 f(i,0,3){
50 ll vx=a+xa[i],vy=b+ya[i];
51 if(dis[vx][vy]>0)
52 //状态连边
53 add(num+d,num+i,dis[vx][vy]);
54 }
55 //交换位置,getnum表示相对位置取反
56 add(num+d,getnum(x,y)+fat(d),1);
57 }
58 ll far[maxm];
59 bool vis[maxm];
60 queue<ll> Q;
61 il void spfa(ll sx,ll sy){//基本的spfa
62 memset(far,-1,sizeof(far));//mem-1可以相当于赋值
63 ll num=getnum(sx,sy);
64 f(i,0,3){
65 ll vx=sx+xa[i],vy=sy+ya[i];
66 if(dis[vx][vy]!=-1){
67 far[num+i]=dis[vx][vy];
68 Q.push(num+i);
69 }
70 }
71 //↑压入起始状态(<=4种)
72 while(!Q.empty()){
73 ll u=Q.front();
74 Q.pop();
75 vis[u]=0;
76 r(i,u){
77 ll v=e[i].to;
78 if(far[v]>far[u]+e[i].w||far[v]==-1){
79 far[v]=far[u]+e[i].w;
80 if(!vis[v]){
81 Q.push(v);
82 vis[v]=1;
83 }
84 }
85 }
86 }
87 }
88 int main()
89 {
90 cin>>n>>m>>q;
91 f(i,1,n) f(j,1,m) cin>>Map[i][j];
92 f(i,1,n){
93 f(j,1,m){
94 if(!Map[i][j]) continue;
95 f(o,0,3){
96 //处理每相邻状态的空格移动的最小步数
97 //包括目标点不动空格动(<=3种),目标空格交换位置(1种)
98 ll x=i+xa[o],y=j+ya[o];
99 if(Map[x][y]) bfs(i,j,x,y,o);
100 }
101 }
102 }
103 ll sx,sy,ex,ey,tx,ty,ans;
104 while(q--){
105 ans=INF;
106 cin>>ex>>ey>>sx>>sy>>tx>>ty;
107 if(sx==tx&&sy==ty){cout<<0<<endl;continue;}
108 bfs(sx,sy,ex,ey,5);
109 //借用bfs求出空格独立行走最短路
110 spfa(sx,sy);
111 ll num=getnum(tx,ty);
112 f(i,0,3)
113 if(far[num+i]!=-1) ans=min(ans,far[num+i]);
114 cout<<((ans==INF)?-1:ans)<<endl;
115 }
116 }
[NOIP2013 提高组] 华容道 P1979 洛谷的更多相关文章
- NOIP2017提高组Day2T3 列队 洛谷P3960 线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/9265380.html 题目传送门 - 洛谷P3960 题目传送门 - LOJ#2319 题目传送门 - Vij ...
- NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp
原文链接https://www.cnblogs.com/zhouzhendong/p/9261079.html 题目传送门 - 洛谷P3959 题目传送门 - Vijos P2032 题意 给定一个 ...
- NOIP 2016 提高组 复赛 Day2T1==洛谷2822 组合数问题
题目描述 组合数表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法.根据组合数的定 义,我们可以给出计算 ...
- NOIP2018&2013提高组T1暨洛谷P5019 铺设道路
题目链接:https://www.luogu.org/problemnew/show/P5019 花絮:普及蒟蒻终于A了一道提高的题目?emm,写一篇题解纪念一下吧.求过! 分析: 这道题我们可以采用 ...
- [NOIP2013提高组]华容道
这道题第一眼看是暴力,然后发现直接暴力会TLE. 把问题转换一下:移动空格到处跑,如果空格跑到指定位置的棋子,交换位置. 这个可以设计一个状态:$[x1][y1][x2][y2]$,表示空格在$(x1 ...
- [NOIp2013提高组]积木大赛/[NOIp2018提高组]铺设道路
[NOIp2013提高组]积木大赛/[NOIp2018提高组]铺设道路 题目大意: 对于长度为\(n(n\le10^5)\)的非负数列\(A\),每次可以选取一个区间\(-1\).问将数列清零至少需要 ...
- NOIP2013 提高组 Day2
期望得分:100+100+30+=230+ 实际得分:100+70+30=200 T2 觉得题目描述有歧义: 若存在2i却不存在2i+1,自己按不合法做的,实际是合法的 T3 bfs 难以估分 虽然 ...
- [NOIP2013提高组]火柴排队
题目:洛谷P1966.Vijos P1842.codevs3286. 题目大意:有两排火柴,每根都有一个高度.设a.b分别表示两排火柴的高度,现在要令$\sum(a_i-b_i)^2$最小.现两排火柴 ...
- [NOIP2013提高组] CODEVS 3287 火车运输(MST+LCA)
一开始觉得是网络流..仔细一看应该是最短路,再看数据范围..呵呵不会写...这道题是最大生成树+最近公共祖先.第一次写..表示各种乱.. 因为要求运输货物质量最大,所以路径一定是在最大生成树上的.然后 ...
随机推荐
- Dapper同时操作任意多张表的实现
1:Dapper的查询帮助类,部分代码,其它新增更新删除可以自行扩展 using Microsoft.Extensions.Configuration; using System; using Sys ...
- 这款打怪升级的小游戏,7 年前出生于 GitHub 社区,如今在谷歌商店有 8 万人打了满分
今天我在 GitHub 摸鱼寻找新的"目标"时,发现了一个开源项目是 RougeLike 类的角色扮演游戏「破碎版像素地牢」(Shattered Pixel Dungeon)类似魔 ...
- Linux内核编译配置脚本
环境 宿主机平台:Ubuntu 16.04.6 目标机:iMX6ULL Linux内核编译配置脚本 在linux开发过程中熟练使用脚本可以大大简化命令行操作,同时对于需要经常重复操作的指令也是一种备忘 ...
- JS020. Array map()函数查到需要的元素时跳出遍历循环,不再执行到数组边界
Array.prototype.map() map( ) 方法创建一个 新数组 *,其结果是该数组中的每个元素是调用一次提供的 函数后的返回值 *.[ MDN / RUNOOB ] * map 添加 ...
- Servlet生命周期和方法
一.五个生命周期方法,有三个很重要,初始化方法.提供服务方法和销毁方法 1.三个主要方法 2.另外两个重写的成员方法只做了解 二.生命周期详解 其中,每次刷新页面都是一次对servlet访问: 页面访 ...
- 前缀树及其Java实现
前缀树 基础知识 Trie树.又称之为单词查找树或者键树,是一种树形结构.应用于统计和排序大量的字符串.常被搜索引擎系统用于文本词频统计.它的优点:能够最大限度的减少无谓的字符串比较,查询效率比哈希表 ...
- React项目中应用TypeScript
一.前言 单独的使用typescript 并不会导致学习成本很高,但是绝大部分前端开发者的项目都是依赖于框架的 例如和vue.react 这些框架结合使用的时候,会有一定的门槛 使用 TypeScri ...
- go中语句为什么不用加分号;结束
不用人加 编译的时候自动加了分号; 编译器工作原理 首先,在一行中,寻找成对的符号,比如一对字符串的引号.一对圆括号,一对大括号 上述任务完成后,在一行中没有其他成对的标示,然后就在行尾追加分号; 所 ...
- 搭建GIT仓库
- POJ3061——Subsequence(尺取法)
Subsequence POJ - 3061 给定长度为n的数列整数a0,a1,a2-an-1以及整数S.求出总和不小于S的连续子序列的长度的最小值,如果解不存在输出0. 反复推进区间的开头和末尾,来 ...