分析

这道题很容易想到令f[x][y][x1][y1]表示空白块在(x,y)、指定棋子在(x1,y1)时的最少步数,让空白块和四周的棋子交换,当空白块要和指定棋子交换时,把指定棋子移动,搞一下BFS就可以了,时间复杂度O(qn2m2),可以拿60+。

因为只有空白块在指定棋子的旁边,指定棋子才能移动,而且指定棋子每次移动后,空白块仍然与指定棋子相邻。所以令move[x][y][k][l]表示指定棋子在(x,y),空白块在与指定棋子相邻的k方向,要将空白块移动到与指定棋子相邻的l方向需要的步数。那么首先把move预处理出来,在每一次讯问中,把空白格移到指定棋子相邻的存在的格子,做一次spfa,就可以了。

spfa:令f[x][y][k]表示指定棋子在(x,y),空白块在与指定棋子相邻的k方向的状态需要的最少步数。转移显然,(xx,yy)是要移动到的方向,i表示指定格子要向i方向走,k1指移动后空白块在与指定棋子相邻的k方向,k1即是i的相反方向,那么f[x][y][k]+move[x][y][k][i]+1==>f[xx][yy][k1]。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
using namespace std;
int n,m,qu,a[40][40]={0},z[4][2]={{0,1},{1,0},{0,-1},{-1,0}},d[1000000][5],move[31][31][5][5],f[31][31][5];
int d1[1000000][5],xx,yy;
bool bz[31][31],b[31][31][5];
int bfs(int x,int y,int k1,int k2)
{
int i,j,k,l,head=0,tail=1,x1=z[k1][0]+x,y1=z[k1][1]+y,x2=z[k2][0]+x,y2=z[k2][1]+y;
int xx,yy;
if(!a[x1][y1] || !a[x2][y2]) return 0;
memset(bz,true,sizeof(bz));
bz[x][y]=false;
d[1][0]=0;
d[1][1]=x1;
d[1][2]=y1;
bz[x1][y1]=false;
while(head<tail)
{
k=++head;
for(i=0;i<=3;i++)
{
xx=d[k][1]+z[i][0];
yy=d[k][2]+z[i][1];
if(bz[xx][yy] && a[xx][yy])
{
d[++tail][0]=d[k][0]+1;
d[tail][1]=xx;
d[tail][2]=yy;
bz[xx][yy]=false;
if(xx==x2 && yy==y2)
{
move[x][y][k1][k2]=d[tail][0];
return 0;
}
}
}
}
return 0;
}
int bk(int x,int y,int x1,int y1)
{
memset(bz,true,sizeof(bz));
d1[0][0]=0;
bz[x][y]=false;
bz[x1][y1]=false;
d[1][0]=0;
d[1][1]=x;
d[1][2]=y;
int head=0,tail=1,i,j,k;
while(head<tail)
{
k=++head;
for(i=0;i<=3;i++)
{
xx=d[k][1]+z[i][0];
yy=d[k][2]+z[i][1];
if(bz[xx][yy] && a[xx][yy])
{
d[++tail][0]=d[k][0]+1;
d[tail][1]=xx;
d[tail][2]=yy;
bz[xx][yy]=false;
}
else
if(xx==x1 && yy==y1)
{
d1[++d1[0][0]][0]=d[k][0];
d1[d1[0][0]][1]=xx;
d1[d1[0][0]][2]=yy;
d1[d1[0][0]][3]=(i+2)%4;
}
}
}
}
int pre()
{
memset(move,43,sizeof(move));
int i,j,k,l;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(a[i][j])
for(k=0;k<=3;k++)
for(l=0;l<=3;l++)
{
if(k==l)
{
move[i][j][k][l]=0;
}
else bfs(i,j,k,l);
}
return 0;
}
int spfa()
{
int i,j,k,l,head=0,tail=d1[0][0];
memset(b,true,sizeof(b));
for(i=1;i<=d1[0][0];i++)
{
f[d1[i][1]][d1[i][2]][d1[i][3]]=d1[i][0];
b[d1[i][1]][d1[i][2]][d1[i][3]]=false;
}
while(head<tail)
{
k=++head;
b[d1[k][1]][d1[k][2]][d1[k][3]]=true;
for(i=0;i<=3;i++)
{
xx=d1[k][1]+z[i][0];
yy=d1[k][2]+z[i][1];
if(f[d1[k][1]][d1[k][2]][d1[k][3]]+move[d1[k][1]][d1[k][2]][d1[k][3]][i]+1<f[xx][yy][(i+2)%4])
{
f[xx][yy][(i+2)%4]=f[d1[k][1]][d1[k][2]][d1[k][3]]+move[d1[k][1]][d1[k][2]][d1[k][3]][i]+1;
if(b[xx][yy][(i+2)%4])
{
b[xx][yy][(i+2)%4]=false;
d1[++tail][1]=xx;
d1[tail][2]=yy;
d1[tail][3]=(i+2)%4;
}
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&qu);
int i,j,k,l;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&a[i][j]);
int p=-1;
pre();
while(qu--)
{
int x,y,x1,y1,x2,y2,head=0,tail=1,xx,yy;
scanf("%d%d%d%d%d%d",&x,&y,&x1,&y1,&x2,&y2);
bk(x,y,x1,y1);
if(x2==x1 && y2==y1)
{
printf("0\n");
}
else
{
memset(f,43,sizeof(f));
int ans=f[0][0][0];
spfa();
for(i=0;i<=3;i++)
ans=min(ans,f[x2][y2][i]);
if(ans==f[0][0][0]) printf("-1\n");
else printf("%d\n",ans);
}
}
}

【华容道】题解(NOIP2013提高组day2)的更多相关文章

  1. NOIP2013 提高组day2 3 华容道 BFS

    描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的 ...

  2. 3537. 【NOIP2013提高组day2】华容道(搜索 + 剪枝)

    Problem 给出一个类似华容道的图.\(q\)次询问,每次给你起始点,终止点,空格位置,让你求最少步数 \(n,m\le 30, q\le 500\). Soultion 一道智障搜索题. 弱智想 ...

  3. NOIP2013 提高组 Day2

    期望得分:100+100+30+=230+ 实际得分:100+70+30=200 T2 觉得题目描述有歧义: 若存在2i却不存在2i+1,自己按不合法做的,实际是合法的 T3  bfs 难以估分 虽然 ...

  4. 积木大赛 noip2013提高组day2

    这道题一开始想到处理中间是0的位置,但这样时间太慢了,后来想到一种类似二分的方法,就是把这一段的最小值找到,全部减去最小值,然后有0一出现,就又递归处理前一段,每次答案就加上这一段的最小值: AC代码 ...

  5. NOIP2013 提高组day2 2 花匠 动规 找拐点 树状数组

    花匠 描述 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致. 具体 ...

  6. Noip2013 提高组 Day2 T1 积木大赛

    题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成 ...

  7. [NOIP2013 提高组] 华容道 P1979 洛谷

    [NOIP2013 提高组] 华容道 P1979 洛谷 强烈推荐,更好的阅读体验 经典题目:spfa+bfs+转化 题目大意: 给出一个01网格图,和点坐标x,y空格坐标a,b,目标位置tx,ty要求 ...

  8. [NOIp2013提高组]积木大赛/[NOIp2018提高组]铺设道路

    [NOIp2013提高组]积木大赛/[NOIp2018提高组]铺设道路 题目大意: 对于长度为\(n(n\le10^5)\)的非负数列\(A\),每次可以选取一个区间\(-1\).问将数列清零至少需要 ...

  9. 18/9/16牛客网提高组Day2

    牛客网提高组Day2 T1 方差 第一眼看就知道要打暴力啊,然而并没有想到去化简式子... 可能因为昨晚没睡好,今天上午困死 导致暴力打了一个半小时,还不对... #include <algor ...

随机推荐

  1. 快速入门分布式消息队列之 RabbitMQ(2)

    目录 目录 前文列表 RabbitMQ 的特性 Message Acknowledgment 消息应答 Prefetch Count 预取数 RPC 远程过程调用 vhost 虚拟主机 插件系统 最后 ...

  2. redis管道pipeline

    Jedis jedis = new Jedis("127.0.0.1",6379); Pipeline pipeline = jedis.pipelined(); for(int ...

  3. 手动设计神经网络进行MNIST分类

    前言: 用手工设计的两层神经网络,经过200个epoch,最后得到0.9599,约0.96的精度 正文 import tensorflow as tf from tensorflow.examples ...

  4. 浅谈JVM及原理

    前言 JVM一直是java知识里面进阶阶段的重要部分,如果希望在java领域研究的更深入,则JVM则是如论如何也避开不了的话题,本系列试图通过简洁易读的方式,讲解JVM必要的知识点. 运行流程 我们都 ...

  5. RPM包或源码包

    安装RPM包或源码包 点击vmware右下角光驱连接. 安装rpm包 -i:表示安装 -v:表示可视化 -h:表示显示安装进度 (同时使用) --force:表示强制安装,即使覆盖属于其他包的文件也要 ...

  6. 多线程16-SpinWait

        );             isCompleted = ));             isCompleted = );             isCompleted = true;    ...

  7. [转帖]解决K8S 安装只有 一直提示:kernel:unregister_netdevice: waiting for eth0 to become free. Usage count = 1 的方法

    Centos7 终端报Message from syslogd :kernel:unregister_netdevice https://www.jianshu.com/p/96d7e2cd9e99 ...

  8. 剑指Offer编程题(Java实现)——链表中倒数第k个结点

    题目描述 输入一个链表,输出该链表中倒数第k个结点. 注意: 该题目不可以用先反转链表再输出第k个结点的方式,因为反转链表会改变该结点的next指向 思路一 使用栈Stack倒序存储,顺序pop第k个 ...

  9. HNUSTOJ-1520 压缩编码

    1520: 压缩编码 时间限制: 1 Sec  内存限制: 2 MB提交: 107  解决: 54[提交][状态][讨论版] 题目描述 某工业监控设备不断发回采样数据.每个数据是一个整数(0到1000 ...

  10. nodejs遍历文件夹下并操作HTML/CSS/JS/PNG/JPG

    需求描述,由于工作的需要,需要将原本用于1280 720的网页改为1920 1080的网页(电视端页面).需求可以拆分为两部分,代码部分的修改以及图片的修改.在代码部分,需要将所有位置以及大小相关的值 ...