分析

这道题很容易想到令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. 阶段3 1.Mybatis_11.Mybatis的缓存_5 缓存的概念

    2.Mybatis中的缓存     什么是缓存         存在于内存中的临时数据.     为什么使用缓存         减少和数据库的交互次数,提高执行效率.     什么样的数据能使用缓存 ...

  2. 【Hibernate】---【注解】一对多

    一.核心配置文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-con ...

  3. SpringContextHolder使用报错

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/dobecoder/article/details/88401612今天在使用SpringContex ...

  4. unittest单元测试1

    一个简单的单元测试例子#coding:utf-8from selenium import webdriverimport unittestclass Baidu(unittest.TestCase): ...

  5. Java中个容器的对比

    List: 有序,列表存储,元素可重复 Set: 无序,元素不可重复 Map:无序,元素可重复,key不能重复 LinkedList :链表,删除和添加效率很高,随机访问效率较ArrayList类低, ...

  6. sentos7网卡改名

    一.已经装好系统CentOS7修改网卡为eth0 1. 修改网卡配置文件[root@localhost ~]# mv /etc/sysconfig/network-scripts/ifcfg-ens3 ...

  7. 8.FTP后门命令执行----Samba命令执行----VMware安装kali----多终端显示

    FTP后门命令执行 再次声明,最近听闻不得教受工具使用等言论. 我敢打包票,网络空间安全一级学科的老师和学生是不会说这句话的.未知攻,焉知防. 有工具来检测自己和玩弄它,是幸运的. 犯罪者不会给你提供 ...

  8. 比较css中单位px,em和rem的区别

    国内的设计师大都喜欢用px,而国外网站大都喜欢用em和rem,那么三者有什么区别,又各自有什么优劣呢? px特点 1. IE无法调整那些使用px作为单位的字体大小: 2. 国外的大部分网站能够调整的原 ...

  9. TortoiseGit不用每次输入用户名和密码的方法

    TortoiseGit每次同步代码时,都会让输入用户名和密码,虽然安全,但是自己用有点麻烦. 怎么解决呢?废话不多说,直接上图: 1.设置—编辑本地.git/config 2.在本地.git/conf ...

  10. nrm安装与配置

    nrm安装与配置:https://blog.csdn.net/anway12138/article/details/79455224