第一次发紫题题解,居然在发布前太激动,把刚写好的还没发布的题解一个Ctrl+A和Backspace全删了。(所以这是二稿)

luogu题目传送门

前置:

做本题一定要有的一些思想:

1、从简思想: 模拟白格子的移动,而千万不要想这去模拟众棋子的移动。这样会简单很多,否则会s的很惨。

2、转换思想(万物皆有其对立面):题目中给的规则,是棋子可以移动到白色格子上。我们将其共轭一下:

白色格子可以移动到棋子上,或者说,白色格子可以和棋子交换位置。

3、白色格子永远只有一个。(看似是废话的大实话)

4、习惯把起点叫做x,终点叫作ht

暴力那些事:

暴力不难实现,就是令空白格子到处移动,然后不断对ans取min就好了。别的题解有很多详细介绍,

在此不过多赘述。

思路获取:

First,从题目基本的信息入手。

如何才能令我们的目标棋子移动?

稍作思考。。。。。。当然是让空白格子在目标旗子旁边啊!!

一个要点get。

Second, 对白色格子全局的移动进行试验:

发现,白色格子的移动可以大致分为两个阶段:不顾一切移向目标棋子,然后在棋子周围打转(因为这样才可以步数最少)

だから(So),我们重点关注的对象,自然就来到了第二阶段上。

不难发现,无论棋子在哪个坐标上,白色格子永远都只会有四种情况:上,下,左,右。

移动后呢?    发现:  从一次移动到下一次移动,白色格子和棋子只会出现两大类移动:

1、白色格子还在棋子周围,只不过是上下左右随机。

2、白色格子直接和棋子位置进行了交换。

再看题目要求:最短路径。

那么,对于第一种情况,我们完全可以用BFS,求出白色格子从上一次位置移动到目前位置的距离。

第二种情况,步数很明显是1.

又一个要点get.

现在考虑,如何对我们的状态进行记录?

考虑用三维数组ok[x][y][k] (坐标x,y + 状态编号k)记录。 (其中k:k = 0,1,2,3,分别对应上下左右即可)

最后,再看一下题目的数据范围:我们完全可以求出(以棋子为中心)所有坐标到相邻坐标的步数。

!!!关系如此密集,何不考虑建图呢?

如果将所有的状态看做一个点,那么他到下一个状态的边权就是他们的步数。如果我们对这个图进行SPFA呢?

在那一串dist中,我们要求的距离,不正是终点ht周围的4个状态对应的dist吗!(取min,废话)

重大要点get!!

At last, 如何对这些状态进行编号,跑SPFA?不能直接用三维数组建图啊!

你需要一个公式:((x - 1) * m + y) * 4 - (4 - k);

至此,这道题也是被我们攻陷了。

后置:

1、一定要注意代码中的细节操作(特别是BFS跑状态的时候)

2、k对应的状态可千万不能忘呀,对应错了后果很严重呀!

码力全开!

#include <bits/stdc++.h>
using namespace std;
#define N 50
#define N2 5005
#define isdigit(c) ((c)>='0'&&(c)<='9')
#define INF (~0u>>1)
const int orz = ; inline int read(){
int x = , s = ;
char c = getchar();
while(!isdigit(c)){
if(c == '-') s = -;
c = getchar();
}
while(isdigit(c)){
x = (x << ) + (x << ) + (c ^ '');
c = getchar();
}
return x * s;
} bool ma[N][N], vis[N][N];
int fx[] = {-, , , };
int fy[] = {, , -, };
int n, m, ex, ey, sx, sy, htx, hty; inline bool judge(int x, int y){
if(x < || y < || x > n || y > m)return ;
return ma[x][y] ;
} inline int getnum(int x, int y, int t){
return ((x - ) * m + y) * - ( - t);
} struct data{
int x ,y;
int step; /*存储每个坐标的信息*/
};
/* sx,sy是否可以到达htx, hty?*/
int bfs(int dx, int dy, int sx, int sy, int htx, int hty){
queue <data> q; /*模拟可移动格子的移动*/
memset(vis, , sizeof(vis));
q.push((data){sx, sy, });
vis[sx][sy] = ; /*从起点开始*/
while(!q.empty()){
data now = q.front();
q.pop();
int x = now.x, y = now.y, step = now.step;
if(x == htx && y == hty){
return now.step; /*如果到达终点*/
}
for(int i = ;i < ; i++){
int l = x + fx[i], r = y + fy[i];
if(judge(l, r)){
if(vis[l][r] || (l == dx && r == dy))continue; /*如果新点已经访问过或者等于现在的*/
q.push((data){l, r, step + });
vis[l][r] = ;
}
}
}
return INF; /*两个点不能互相到达*/
} struct node{
int u, v, w;
int next;
} t[N2];
int f[N2]; int bian = ;
void add(int u, int v, int w){
t[++bian].u = u;
t[bian].v = v;
t[bian].w = w;
t[bian].next = f[u];
f[u] = bian;
return ;
} /*预处理, 找出所有可行状态*/ bool ok[N][N][];
void prepare(){
for(int i = ;i <= n; i++)
for(int j = ;j <= m; j++)
if(ma[i][j])
for(int k = ;k < ; k++)
if(judge(i+fx[k], j+fy[k]))
ok[i][j][k] = ;
for(int i = ;i <= n; i++) /*空白格子围绕棋子旋转时*/
for(int j = ;j <= m; j++)
for(int k = ;k < ; k++)
for(int l = k + ; l < ; l++) /*枚举不同的方向*/
if(ok[i][j][k] && ok[i][j][l]){
int a = getnum(i, j, k), b = getnum(i, j, l);
int c = bfs(i, j, i + fx[k], j + fy[k], i + fx[l], j + fy[l]);
if(c != INF){ /*状态之间是否可达*/
add(a, b, c);
add(b, a, c);
}
}
for(int i = ;i <= n; i++) /*空白格子和棋子交换位置*/
for(int j = ;j <= m; j++){
if(ok[i][j][] && ok[i][j+][]){
int a = getnum(i, j, ); /*几种小情况*/
int b = getnum(i, j+, );
add(a, b, );
add(b, a, );
}
}
for(int i = ;i <= n; i++)
for(int j = ;j <= m; j++){
if(ok[i][j][] && ok[i+][j][]){
int a = getnum(i, j, );
int b = getnum(i+, j, );
add(a, b, );
add(b, a, );
}
}
return ;
} /*进行最短路求解*/ queue <int> q;
bool viss[N2];
int d[N2]; int spfa(){
memset(d, , sizeof(d));
memset(viss, , sizeof(viss));
int flag = d[]; /*之后判断用的*/
for(int i = ;i < ; i++){ /*先对起点进行选取*/
int l = sx + fx[i], r = sy + fy[i];
if(judge(l, r)){
int temp = bfs(sx, sy, ex, ey, l, r); /*ex,ey 是否可以到达 l,r? */
if(temp != INF){
int snum = getnum(sx, sy, i);
viss[snum] = ;
q.push(snum);
d[snum] = temp;
}
}
}
while(!q.empty()){ /*求所有状态间的最短路*/
int now = q.front(); q.pop();
viss[now] = ;
for(int i = f[now]; i;i = t[i].next){
int u = t[i].u, v = t[i].v, w = t[i].w;
if(d[v] > d[u] + w){
d[v] = d[u] + w;
if(!viss[v]){
viss[v] = ;
q.push(v);
}
}
}
}
int ans = INF;
for(int i = ; i < ; i++){
int num = getnum(htx, hty, i);
ans = min(ans, d[num]);
}
return ans == flag ? - : ans;
} int main(){
// freopen("hh.txt", "r", stdin);
n = read(), m = read();
int T = read();
for(int i = ;i <= n; i++)
for(int j = ;j <= m; j++)
ma[i][j] = read();
prepare();
while(T--){ /*e: 空白 s: 起点 ht: 终点*/
ex = read(), ey = read(), sx = read(), sy = read(), htx = read(), hty = read();
if(sx == htx && sy == hty){ /*特判*/
puts("");
continue;
}
if(!ma[htx][hty] || !ma[sx][sy]){ /*如果起点终点根本不在图内*/
puts("-1");
continue;
}
printf("%d\n", spfa());
}
return orz; /*向大佬势力低头 同时拜一下CCf求AC*/
}

(二稿真累)

华容道题解 NOIP2013 思路题!的更多相关文章

  1. 51nod P1305 Pairwise Sum and Divide ——思路题

    久しぶり! 发现的一道有意思的题,想了半天都没有找到规律,结果竟然是思路题..(在大佬题解的帮助下) 原题戳>>https://www.51nod.com/onlineJudge/ques ...

  2. Leetcode 简略题解 - 共567题

    Leetcode 简略题解 - 共567题     写在开头:我作为一个老实人,一向非常反感骗赞.收智商税两种行为.前几天看到不止两三位用户说自己辛苦写了干货,结果收藏数是点赞数的三倍有余,感觉自己的 ...

  3. POJ 1904 思路题

    思路: 思路题 题目诡异地给了一组可行匹配 肯定有用啊-. 就把那组可行的解 女向男连一条有向边 如果男喜欢女 男向女连一条有向边 跑一边Tarjan就行了 (这个时候 环里的都能选 "增广 ...

  4. BZOJ 3252: 攻略(思路题)

    传送门 解题思路 比较好想的一道思路题,结果有个地方没开\(long\) \(long\) \(wa\)了三次..其实就是模仿一下树链剖分,重新定义重儿子,一个点的重儿子为所有儿子中到叶节点权值最大的 ...

  5. BZOJ 1303: [CQOI2009]中位数图(思路题)

    传送门 解题思路 比较好想的思路题.首先肯定要把原序列转化一下,大于\(k\)的变成\(1\),小于\(k\)的变成\(-1\),然后求一个前缀和,还要用\(cnt[]\)记录一下前缀和每个数出现了几 ...

  6. [NOIP2013]华容道 题解

    [NOIP2013]华容道 首先是一种比较显然的做法. 整个棋盘,除了起点,终点和空格,其他的方块是等价的. 对于终点,它始终不会变化,如果搜到终点结束搜索即可,所以我们不需要考虑终点. 所以需要考虑 ...

  7. [NOIP2013]华容道 题解(搜索)

    [NOIP2013]华容道 [题目描述] 这道题根据小时候玩华容道不靠谱的经验还以为是并查集,果断扑街.考后想想也是,数据这么小一定有他的道理. 首先由于是最小步数,所以BFS没跑了.那么我们大可把这 ...

  8. ACM 杂题,思路题 整理

    UVa 11572 - Unique Snowflakes 问一个数组中,无重复数字的最长子串长度是多少. 用map维护某数字上次出现的位置.另外用变量last表示上次出现数字重复的位置. 如果出现重 ...

  9. 【思路题】【多校第一场】【1001.OO’s Sequence】

    题目大意: 给你一个序列A,f(l,r) 表示 在[l,r]中 的Ai 对于每一个数Aj 都有 Ai%Aj!=0  的数目(  i!=j  ) 卡了一段时间..... 题解 简单题 定义两个数组L[i ...

随机推荐

  1. 数学--数论--HDU1222 狼和兔子(最大公约数)

    问题描述 有一座周围有n个洞的小山.孔从0到n-1有符号. 兔子必须藏在其中一个洞中.狼以逆时针方向搜索兔子.他第一个进入的洞是一个用0签名的洞.然后,他将每m个洞进入一个洞.例如,m = 2和n = ...

  2. 图论--差分约束--POJ 3169 Layout(超级源汇建图)

    Like everyone else, cows like to stand close to their friends when queuing for feed. FJ has N (2 < ...

  3. 2019 Multi-University Training Contest 10 I Block Breaker

    Problem Description Given a rectangle frame of size n×m. Initially, the frame is strewn with n×m squ ...

  4. python(json 模块)

    1.Json 定义 定义:JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式.JSON 的数据格式其实就是 python 里面的字典格式,里 ...

  5. Intersection of Two Linked Lists (求两个单链表的相交结点)

    题目描述: Write a program to find the node at which the intersection of two singly linked lists begins. ...

  6. 从一条数据说起——InnoDB存储数据结构

    本篇博客参考掘金小册--MySQL 是怎样运行的:从根儿上理解 MySQL 先给大家讲一个故事,我刚参加工作,在一个小作坊里面当[码畜](尽管现在也是),有一天老板从我背后走过,说了一句举世震惊的话: ...

  7. Educational Codeforces Round 77 (Rated for Div. 2) C. Infinite Fence

    C. Infinite Fence 题目大意:给板子涂色,首先板子是顺序的,然后可以涂两种颜色,如果是r的倍数涂成红色,是b的倍数涂成蓝色, 连续的k个相同的颜色则不能完成任务,能完成任务则输出OBE ...

  8. while(scanf("%d",&n)!=EOF) / while(cin>>n)终止问题

    问题的发现:(想要看干货可以直接跳过这段) 我最近刚了解到关于栈的用法,于是按照参考书寻找代码,并把它敲到电脑上.编译运行代码后发现无法终止,在网上查找各种资料,总结如下. 因为我的电脑是Window ...

  9. 【BIM】BIMFACE中实现电梯实时动效

    背景 在运维场景中,电梯作为运维环节重要的一部分是不可获缺的,如果能够在三维场景中,将逼真的电梯效果,包括外观.运行状态等表现出来,无疑是产品的一大亮点.本文将从无到有介绍如何在bimface中实现逼 ...

  10. Vue + Element-ui实现后台管理系统(5)---封装一个Form表单组件和Table表格组件

    封装一个Form表单组件和Table组件 有关后台管理系统之前写过四遍博客,看这篇之前最好先看下这四篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-syste ...