[luogu1979] 华容道
题面
先讲点无关的,这道题是真的恶心...
好了,第一眼看到这道题,肯定是准备暴搜的,但是想了一想,省选难度的题目不可能一上来就让你暴搜吧,于是开启了无穷无尽的分析,我们不妨设指定棋子叫做移动棋,所以题目的目标就是利用一个空格子,将移动棋移动至目标点,然后就开始想怎么移动呢???
如果移动棋上下左右都是棋子的话,肯定不能移动,所以必定要一个空格子来把棋子移出去,所以棋子移动的条件便是周围有空格子,此时可以把移动棋移动至空格子处,空格子就到了移动棋原来的位置上,这样往返,不断地将空格子移至移动棋旁边,这样就可以将移动棋一步步地向目标点移去,所以移动的方面分析完了,接下来分析如何把当前的状态表示出来呢???
我们可以设一个三元对(x, y, k)代表点(x, y)的 k 方向为空格子,不妨设空格子的坐标为(a, b, k)此时我们有两种操作:①:将 k 的值变更,即当前点不动,将空格子移至当前点的其他的方位;②:交换当前点与空格子,此时当前点的坐标变为原来空格子的坐标,那么空格子所对的方向是什么呢???我们不妨设上右下左为0,1,2,3,则原来点的坐标变为(a, b, (k + 2) % 4)(空格子由上变下,下变上,左变右,右变左)。所以我们可以先预处理一下每个可以移动的棋子的这几种情况。
预处理代码
inline void BFS(int t)
{
memset(d, -1, sizeof(d)); mapp[xa][ya] = 0;
queue <node> q;
q.push((node) { xb, yb }); d[xb][yb] = 0;
while(!q.empty())
{
node tmp = q.front(); q.pop();
for(int k = 0; k < 4; k++)
{
int tx = tmp.x + xx[k], ty = tmp.y + yy[k];
if(d[tx][ty] != -1 || !mapp[tx][ty]) continue;
d[tx][ty] = d[tmp.x][tmp.y] + 1; q.push((node) { tx, ty });
}
}
mapp[xa][ya] = 1;
if(t == 4) return; //每次询问时,从空格向起点跑计算出d数组后就不需要再加边了.
for(int k = 0; k < 4; k++)
{
int tx = xa + xx[k], ty = ya + yy[k];
if(d[tx][ty] != -1) add(xa * 120 + ya * 4 + t, xa * 120 + ya * 4 + k, d[tx][ty]);
//状态为点,状态的转移为边,长度为所需要的最少步数.
}
add(xa * 120 + ya * 4 + t, xb * 120 + yb * 4 + (t + 2) % 4, 1); //交换所需要的最少步数
}
在这之后,每对于一次询问,我们就可以先将空格子移动至移动棋的四个方向的最少步数算出来,在这里,我们要使用一种思想,就是说,将每个三元对(x, y, k)化为一个一维的状态,x * 120 + y * 4 + k(我们其实可以把这个三元对看做一个百位为x,十位为y,个位为k的一个数,其中个位逢4进1,因为k只有四种可能,十位逢30进1,因为y<=30,百位逢120进1,因为每一个y有4种可能,又有30个y,所以x便逢120进1,这样保证了不同种状态不会表示同一个数),最后以各个状态为点,状态的转移为边(也就是这两种情况的转移所需要的最少步数),跑一遍SPFA,最后统计空格在终点的四个方向的最小值就可以了。
完整代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
int n, m, Q, head[5005], cnt, mapp[37][37], xa, xb, ya, yb, ex, ey, d[37][37], dis[5005], vis[5005], xx[4] = { 0, 1, 0, -1 }, yy[4] = { 1, 0, -1, 0 };
struct node
{
int x, y;
};
struct Edge
{
int to, next, cost;
} edge[20005];
inline int read()
{
int x = 0, w = 1;
char c = getchar();
while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * w;
}
inline void add(int u, int v, int w) { edge[++cnt].to = v; edge[cnt].cost = w; edge[cnt].next = head[u]; head[u] = cnt; }
inline void BFS(int t)sousuo
{
memset(d, -1, sizeof(d)); mapp[xa][ya] = 0;
queue <node> q;
q.push((node) { xb, yb }); d[xb][yb] = 0;
while(!q.empty())
{
node tmp = q.front(); q.pop();
for(int k = 0; k < 4; k++)
{
int tx = tmp.x + xx[k], ty = tmp.y + yy[k];
if(d[tx][ty] != -1 || !mapp[tx][ty]) continue;
d[tx][ty] = d[tmp.x][tmp.y] + 1; q.push((node) { tx, ty });
}
}
mapp[xa][ya] = 1;
if(t == 4) return;
for(int k = 0; k < 4; k++)
{
int tx = xa + xx[k], ty = ya + yy[k];
if(d[tx][ty] != -1) add(xa * 120 + ya * 4 + t, xa * 120 + ya * 4 + k, d[tx][ty]);
}
add(xa * 120 + ya * 4 + t, xb * 120 + yb * 4 + (t + 2) % 4, 1);
}
inline void SPFA()
{
queue<int> q;
memset(dis, 127, sizeof(dis)); memset(vis, 0, sizeof(vis));
for(int i = 0; i < 4; i++)
{
int tx = xa + xx[i], ty = ya + yy[i]; int id = xa * 120 + ya * 4 + i;
if(d[tx][ty] != -1) { q.push(id); vis[id] = 1; dis[id] = d[tx][ty]; }
//空格有可能到起点的四种方向,需要都统计进去.
}
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if(dis[v] > dis[u] + edge[i].cost)
{
dis[v] = dis[u] + edge[i].cost;
if(!vis[v]) { vis[v] = 1; q.push(v); }
}
}
vis[u] = 0;
}
}
int main()
{
n = read(); m = read(); Q = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
mapp[i][j] = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
if(!mapp[i][j]) continue;
xa = i; ya = j;
for(int k = 0; k < 4; k++)
{
xb = xa + xx[k]; yb = ya + yy[k];
if(mapp[xb][yb]) BFS(k);
}
}
while(Q--)
{
xb = read(); yb = read(); xa = read(); ya = read(); ex = read(); ey = read();
if(xa == ex && ya == ey) { puts("0"); continue; }
BFS(4); SPFA(); int ans = 2e9 + 7;
for(int i = 0; i < 4; i++) ans = min(ans, dis[ex * 120 + ey * 4 + i]);
printf("%d\n", ans == 2e9 + 7 ? -1 : ans);
}
return 0;
}
完
[luogu1979] 华容道的更多相关文章
- luogu1979 华容道 (dijkstra+bfs)
我想动某个点的话,一定要先把空白点移动到这个点旁边,然后调换这个点和空白点,一直重复 那么,我们就可以记一些状态(x,y,s) (s={0,1},{0,-1},{1,0},{-1,0}),表示我要动的 ...
- Luogu1979 NOIP2013D2T3 华容道 搜索、最短路
题目传送门 题意:给出一个$N \times M$的棋盘,棋盘上有一些块可以移动,有一些块无法移动.$Q$次询问,每一次询问给出三个块$a,b,c$,将$a$块变为空格,空格旁边可移动的块可以与空格交 ...
- [Luogu1979][NOIP2013]华容道(BFS+SPFA)
考虑从起点到终点的过程,一定是先将空格子移到指定格子旁边,和指定格子交换,再移到下一个指定格子要到的地方,再交换,如此反复. 于是问题分为两个部分: 1.给定两个曼哈顿距离为2的格子求最短路,BFS即 ...
- [NOIP2013]华容道
1.题面 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间.小 B 玩的华容道与经典 ...
- codevs 3290 华容道(SPFA+bfs)
codevs 3290华容道 3290 华容道 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description 小 B 最近迷上了华容道,可是 ...
- NOIP2013 提高组day2 3 华容道 BFS
描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的 ...
- 【NOIP2013】华容道
看别人的代码然后被坑了一下午+一晚上,睡一觉第二天醒悟过来打表过了 果然打表才是正确的调试方法,跟踪什么的去屎(╯‵□′)╯︵┻━┻ 原题: 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成 ...
- 【NOIP 2013 DAY2 T3】 华容道(spfa)
题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 ...
- 搜索(另类状态BFS):NOIP 华容道
描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的 ...
随机推荐
- Java基础——封装类
封装类的由来: 为了将基本类型以对象行使存在,java对八个基本类型提供了引用类型,这八个引用类型称为基本类型的“包装类”. 八个基本类型对应的封装类: int ---> ...
- linux环境下mysql 5.7.1X 如何重置root密码
1,vi /etc/my.cnf [mysqld]下加入参数skip-grant-tables 保存退出. 2,重启mysql [root@21yunwei src]# /etc/init.d/ ...
- vue项目使用vue-i18n和iView切换多语言
效果图: 当然,如果使用iview组件,组件也会对应切换语言. 这里,假设已经用vue-cli脚手架创建了项目,熟悉vue-router,而且已经引入了iview UI. 第一步: 我们在main.j ...
- axios中设置post请求,后台却无法识别参数
场景:在使用iview时,定义api请求时,代码如下 export const delWord = (data) => { return axios.request({ url: '/words ...
- Qt Quick程序的发布
要将程序发布出去,首先需要使用release方式编译程序,然后将生成的.exe可执行文件和需要的库文件发在一起打包进行发布. 要确定需要哪些动态库文件,可以直接双击.exe文件,提示缺少那个dll文件 ...
- 浅谈搜索引擎SEO(HTML/CSS)
SEO:搜索引擎优化(免费): SEM:搜索引擎营销(付费). 它们两者的区别是: 1.SEM高投入,SEO低投入: 2.SEM短.效益块,SEO长期投入.增长慢: 3.新广告法颁布之后SEM广告位减 ...
- 算法之杨辉三角形(Java语言)
杨辉三角形, 又称贾宪三角形.帕斯卡三角形. 前9层写出来如下: 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 ...
- 在 O(1) 时间删除链表结点(C 和 Python 实现)
(说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 给定单向链表的头指针和一个结点指针,定义一个函数在 O(1) ...
- Sqlite EF6注册
在EF6使用Sqlite的时候.Sqlite需要安装sqlite-netFx40-setup-bundle-x64-2010-1.0.97.0.exe.我不想在项目发布的时候,安装的时候执行该程序,于 ...
- December 06th 2016 Week 50th Tuesday
Behind every beautiful thing, there is some kind of pain. 美丽背后,必有努力. No pains, no gains. But it seem ...