题目: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. Django之CBV和FBV

    Django之CBV和FBV CBV和FBV是C和F的区别: C是Class,F是Function 在请求中,有GET请求和POST请求. 在写CBV时,url是可以对应一个类的,在类中,分别写出GE ...

  2. virtualenvwrapper.sh: There was a problem running the initialization hooks. If Python could not import the module virtualenvwrapper.hook_loader, check that virtualenvwrapper.........(解决办法)

    Linux(ubuntu)上python2与python3共存环境下,安装virtualenvwrapper后, 其环境变量被自动设置为VIRTUALENVWRAPPER_PYTHON=/usr/bi ...

  3. Java中的日期、时间操作

    每次在处理日期时间的时候都要打开chrome查找一番,索性自己找一下满意的记录下来. 一.时间格式 // hh表示12小时制: HH表示24小时制 SimpleDateFormat format1 = ...

  4. Vue如何使用vue-awesome-swiper实现轮播效果

    在Vue项目中如何实现轮播图的效果呢,在传统项目中第一个想到的一般都是swiper插件,代码简单好用.一开始我也是直接npm安装swiper然后照着之前的传统写法写,然而却没有效果,只会显示图片但没有 ...

  5. $(document).ready() 与$(window).load()

    虽说很早就开始接触JavaScript,自己也用JavaScript编写过许多代码,如之前的web版码表计时器,就写了近500行代码,函数也写了10个左右.当时也就是想到哪里就写到哪里,行不通就另外找 ...

  6. [1143] [CTSC2008]祭祀river(最大独立集 || 偏序集最大反链)

    传送门 网上说这是偏序集最大反链,然而我实在不理解. 所以我换了一个思路,先用floyd,根据点的连通性连边, 问题就转换成了找出最多的点,使任意两个点之间不连边,也就是最大独立集. ——代码 #in ...

  7. 【IntelliJ】IntelliJ IDEA的安装破解及使用

    结合两位大牛CV的,写的很全面,仅供自己使用 转载地:http://www.jianshu.com/p/ad3830095fb3 https://www.cnblogs.com/kangjianwei ...

  8. Linux下汇编语言学习笔记22 ---

    这是17年暑假学习Linux汇编语言的笔记记录,参考书目为清华大学出版社 Jeff Duntemann著 梁晓辉译<汇编语言基于Linux环境>的书,喜欢看原版书的同学可以看<Ass ...

  9. Educational Codeforces Round 41 B、C、D

    http://codeforces.com/contest/961 B题 可以将长度为k的连续区间转化成1 求最大和 解析 简单尺取 #include <stdio.h> #include ...

  10. POJ3295 Tautology 解题报告

    直接上分析: 首先 弄清各种大写字母的操作的实质 K 明显 是 and   & A 是 or      | N 是 not   ! C  由表格注意到 当 w<=x 时 值为1 E  当 ...