题目:https://www.luogu.org/problemnew/show/P1979

真是一道好题...

首先考虑暴力做法,应该是设 f[i][j][x][y] 记录指定棋子和空格的位置,然后 bfs 转移;

然后发现,这些状态中有很多无用的,换句话说,就是仅当空格在指定棋子旁边时才有用,能带来棋子的移动;

所以不妨只记录 f[i][j][k] ,k 表示空格在指定棋子 (i,j) 的哪个方向;

两种转移:1.指定棋子不动,空格从它的一边移动到另一边;

2.指定棋子和空格交换位置;

所以给可以相互转移的状态之间连边,SPFA 跑最短路;

初始状态空格不一定在指定棋子旁边,所以专门 bfs 一下,得到空格在指定棋子旁边的状态;

由于空格可以在指定棋子的四个方向,所以要跑多源最短路;

连边时给每个状态直接记一个 id 比较方便;

调了半天终于65分,加个特判:起点就是终点时输出0,就 A 了~

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const xn=,xm=,inf=1e9;
int n,m,Q,f[xn][xn][][],id[xn][xn][],dx[]={-,,,},dy[]={,,-,};//0,1,2,3 -> 上下左右
int hd[xm],ct,to[xm<<],nxt[xm<<],dis[xm<<],w[xm<<];
bool v[xn][xn],vis[xn][xn],vis2[xm];
struct N{int x,y,d;};
queue<N>q;
queue<int>q2;
void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;}
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return f?ret:-ret;
}
bool ck(int x,int y){return x>=&&x<=n&&y>=&&y<=m&&!v[x][y];}
int bfs(int x,int y,int p1,int p2)
{
while(q.size())q.pop();
memset(vis,,sizeof vis);
int sx=x+dx[p1],sy=y+dy[p1];
int xx=x+dx[p2],yy=y+dy[p2];
if(!ck(sx,sy)||!ck(xx,yy))return inf;
q.push((N){sx,sy,});
vis[sx][sy]=; vis[x][y]=;//!!
while(q.size())
{
int tx=q.front().x,ty=q.front().y,d=q.front().d; q.pop();
for(int i=,nx,ny;i<;i++)
{
nx=tx+dx[i]; ny=ty+dy[i];
if(!ck(nx,ny)||vis[nx][ny])continue;
if(nx==xx&&ny==yy)return d+;
else q.push((N){nx,ny,d+}),vis[nx][ny]=;
}
}
return inf;
}
void init()
{
int cnt=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
for(int k=;k<;k++)
{
id[i][j][k]=++cnt;
if(v[i][j])continue;
for(int l=k+;l<;l++)
f[i][j][k][l]=bfs(i,j,k,l);
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
for(int k=;k<;k++)
{
int x=i+dx[k],y=j+dy[k],a=id[i][j][k],b;
if(!ck(x,y))continue;
// for(int l=0;l<4;l++) //i,j表示指定棋子位置,不可有共用空格的点之间连0的边!(否则没算上指定棋子的移动代价)
// {
// int nx=x+dx[l],ny=y+dy[l];
// if(!ck(nx,ny)||(nx==i&&ny==j))continue;
// b=id[nx][ny][l^1];
// add(a,b,0); add(b,a,0);
// }
if(v[i][j])continue;
for(int l=k+;l<;l++)
{
int nx=i+dx[l],ny=j+dy[l];
if(!ck(nx,ny)||f[i][j][k][l]==inf)continue;
b=id[i][j][l];
add(a,b,f[i][j][k][l]); add(b,a,f[i][j][k][l]);
}
b=id[x][y][k^];
add(a,b,); add(b,a,);
}
}
int is(int x,int y,int xx,int yy)
{
for(int k=;k<;k++)
if(x+dx[k]==xx&&y+dy[k]==yy)return k;
return -;
}
int work(int ex,int ey,int sx,int sy,int tx,int ty)
{
while(q.size())q.pop(); while(q2.size())q2.pop();
memset(vis,,sizeof vis);
memset(vis2,,sizeof vis2);
memset(dis,0x3f,sizeof dis);
q.push((N){ex,ey,}); vis[ex][ey]=;
vis[sx][sy]=;//!!
int k=is(sx,sy,ex,ey),bh;
if(k!=-)q2.push(bh=id[sx][sy][k]),vis2[bh]=,dis[bh]=;
while(q.size())
{
int x=q.front().x,y=q.front().y,d=q.front().d; q.pop();
for(int i=;i<;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if(!ck(tx,ty)||vis[tx][ty])continue;
int k=is(sx,sy,tx,ty); int bh;
if(k!=-)q2.push(bh=id[sx][sy][k]),vis2[bh]=,dis[bh]=d+;
q.push((N){tx,ty,d+});
vis[tx][ty]=;
}
}
while(q2.size())
{
int x=q2.front(); q2.pop(); vis2[x]=;
for(int i=hd[x],u;i;i=nxt[i])
{
u=to[i];
if(dis[u=to[i]]>dis[x]+w[i])
{
dis[u]=dis[x]+w[i];
if(!vis2[u])q2.push(u),vis2[u]=;
}
}
}
int ans=inf;
for(int k=;k<;k++)ans=min(ans,dis[id[tx][ty][k]]);
if(ans==inf)return -;
return ans;
}
int main()
{
n=rd(); m=rd(); Q=rd();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)v[i][j]=!rd();
init();
for(int i=,ex,ey,sx,sy,tx,ty;i<=Q;i++)
{
ex=rd(); ey=rd(); sx=rd(); sy=rd(); tx=rd(); ty=rd();
if(sx==tx&&sy==ty)printf("0\n");//!!!
else printf("%d\n",work(ex,ey,sx,sy,tx,ty));
}
return ;
}

洛谷 P1979 [ NOIP 2013 ] 华容道 —— bfs + 最短路的更多相关文章

  1. 洛谷 P3953 [ NOIP 2017 ] 逛公园 —— 最短路DP

    题目:https://www.luogu.org/problemnew/show/P3953 主要是看题解...还是觉得好难想啊... dfs DP,剩余容量的损耗是边权减去两点最短路差值...表示对 ...

  2. Luogu 1979 NOIP 2013 华容道(搜索,最短路径)

    Luogu 1979 NOIP 2013 华容道(搜索,最短路径) Description 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面 ...

  3. 洛谷模拟NOIP考试反思

    洛谷模拟NOIP考试反思 想法 考了这么简单的试qwq然而依然emmmmmm成绩不好 虽然本次难度应该是大于正常PJ难度的但还是很不理想,离预估分数差很多qwq 于是就有了本反思嘤嘤嘤 比赛链接 原比 ...

  4. 【noip】跟着洛谷刷noip题2

    noip好难呀. 上一个感觉有点长了,重开一个. 36.Vigenère 密码 粘个Openjudge上的代码 #include<cstdio> #include<iostream& ...

  5. 洛谷 P3951 NOIP 2017 小凯的疑惑

    洛谷 P3951 NOIP 2017 小凯的疑惑 题目描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付 ...

  6. 洛谷 P1979 华容道 解题报告

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

  7. Luogu P1979 华容道(bfs+最短路)

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

  8. 【noip】跟着洛谷刷noip题

    传送门 1.铺地毯 d1t1 模拟 //Twenty #include<cstdio> #include<cstdlib> #include<iostream> # ...

  9. 洛谷 P5304 [GXOI/GZOI2019]旅行者(最短路)

    洛谷:传送门 bzoj:传送门 参考资料: [1]:https://xht37.blog.luogu.org/p5304-gxoigzoi2019-lv-xing-zhe [2]:http://www ...

随机推荐

  1. python字符串,常用编码

    Python的字符串和编码 1.常用编码 与python有关的编码主要有:ASCII.Unicode.UTF-8 其中ASCII如今可以视作UTF-8的子集 内存中统一使用Unicode编码(如记事本 ...

  2. 【05】AJAX实例-检测用户名是否存在(实例)

    AJAX实例-检测用户名是否存在   用户注册时,需要填写个人信息,其中包括用户名.当用户输入完成时,JavaScript 需要及时检测用户名是否存在,如果存在给出提示,请用户更换用户名. 当然,这个 ...

  3. openjudge1944 吃糖果

    描述名名的妈妈从外地出差回来,带了一盒好吃又精美的巧克力给名名(盒内共有 N 块巧克力,20 > N >0).妈妈告诉名名每天可以吃一块或者两块巧克力.假设名名每天都吃巧克力,问名名共有多 ...

  4. 在mysql数据库中,文章表设计有啥好的思路

    Q: 用mysql设计一张文章表,不知道有啥好的思路! 我是这样的,应为考虑附件和图片,所以我的文章表除了有varchar(1000)的文章内容,还设置了个Bolb接收附件和图片. 我用的是mysql ...

  5. P1230 智力大冲浪 洛谷

    https://www.luogu.org/problem/show?pid=1230 题目描述 小伟报名参加中央电视台的智力大冲浪节目.本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每 ...

  6. 输入一个URL之后。。。

    1.输入URL2.浏览器去浏览器缓存.系统缓存.路由器缓存查找缓存记录,有则直接访问URL对应的IP,无则下一步3.DNS解析URL,获得对应的IP4.浏览器通过TCP/IP三次握手连接服务器5.客户 ...

  7. fetch各种报跨域错误,数据无法获取的解决方案

    1.介绍 fetch 提供了一个获取资源的接口 (包括跨域). fetch 的核心主要包括:Request , Response , Header , Body 利用了请求的异步特性 --- 它是基于 ...

  8. 我的arcgis培训照片12

    来自:http://www.cioiot.com/successview-381-1.html

  9. python性能优化、内存优化、内存泄露;与其他语音比较效率如何?

    1.内存泄露:http://www.cnblogs.com/xybaby/p/7491656.html 2.内存优化:http://www.cnblogs.com/xybaby/p/7488216.h ...

  10. 旧瓶新酒之ngx_lua & fail2ban实现主动诱捕

    服务器承担着业务运行及数据存储的重要作用,因此极易成为攻击者的首要目标.如何对业务服务器的安全进行防护,及时找出针对系统的攻击,并阻断攻击,最大程度地降低主机系统安全的风险程度,是企业安全从业人员面临 ...