题目: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. win7 x64安装glpk

    下载glpk,下载地址:http://ftp.gnu.org/gnu/glpk/

  2. stark组件之添加、修改页面内容搭建(七)

    如何快速的进行数据的添加以及修改呢?modelform来实现是可以达到效果的,在这里就是应用了modelform,每一个表都不同,所以需要创建不同的modelform. def get_model_f ...

  3. JS 比较运算符 逻辑运算符

    逻辑运算符 三元运算符 摘自:http://www.w3school.com.cn/js/js_comparisons.asp

  4. 集训第四周(高效算法设计)O题 (构造题)

    A permutation on the integers from 1 to n is, simply put, a particular rearrangement of these intege ...

  5. python接口测试之Http请求(三)

    python的强大之处在于提供了很多的标准库,这些标准库可以直接调用,本节部分,重点学习和总结在 接口测试中Python的Http请求的库的学习. 首先来看httplib,官方的解释为:本模块定义了类 ...

  6. POJ 1741 Tree【Tree,点分治】

    给一棵边带权树,问两点之间的距离小于等于K的点对有多少个. 模板题:就是不断找树的重心,然后分开了,分治,至少分成两半,就是上限为log 然后一起统计就ok了 #include<iostream ...

  7. linux network name space

    linux network namespace概念类似于网络中的 VRF (virtual routing and forwarding).但是,你不知道VRF的概念也没关系,下面我们通过一个简单的介 ...

  8. kill杀死进程方法

    查找进程:ps -ef | grep firefox kill -s 9 1827

  9. js获取上传的文件名称

    <input name="file_" type="file" id="file_" size="100" /&g ...

  10. 【CV论文阅读】+【搬运工】LocNet: Improving Localization Accuracy for Object Detection + A Theoretical analysis of feature pooling in Visual Recognition

    论文的关注点在于如何提高bounding box的定位,使用的是概率的预测形式,模型的基础是region proposal.论文提出一个locNet的深度网络,不在依赖于回归方程.论文中提到locne ...