题目描述

【问题描述】

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

小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:

  1. 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;

  2. 有些棋子是固定的,有些棋子则是可以移动的;

  3. 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。

游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。

给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的, 但是棋盘上空白的格子的初始位置、 指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次

玩的时候, 空白的格子在第 EXi 行第 EYi 列,指定的可移动棋子的初始位置为第 SXi 行第 SYi列,目标位置为第 TXi 行第 TYi 列。

假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。

输入输出格式

输入格式:

输入文件为 puzzle.in。

第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;

接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。接下来的 q 行,每行包含 6 个整数依次是 EXi、EYi、SXi、SYi、TXi、TYi,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。

输出格式:

输出文件名为 puzzle.out。

输出有 q 行,每行包含 1 个整数,表示每次游戏所需要的最少时间,如果某次游戏无法完成目标则输出−1。

输入输出样例

输入样例#1:

3 4 2
0 1 1 1
0 1 1 0
0 1 0 0
3 2 1 2 2 2
1 2 2 2 3 2
输出样例#1:

2
-1

说明

【输入输出样例说明】

棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。

  1. 第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2, 2)(图中红色的格子)上。

移动过程如下:

  1. 第二次游戏,空白格子的初始位置是(1, 2)(图中空白所示),游戏的目标是将初始位置在(2, 2)上的棋子(图中绿色圆圈所示)移动到目标位置 (3, 2)上。

要将指定块移入目标位置,必须先将空白块移入目标位置,空白块要移动到目标位置,必然是从位置(2, 2)上与当前图中目标位置上的棋子交换位置,之后能与空白块交换位置的只有当前图中目标位置上的那个棋子,因此目标棋子永远无法走到它的目标位置, 游戏无

法完成。

【数据范围】

对于 30%的数据,1 ≤ n, m ≤ 10,q = 1;

对于 60%的数据,1 ≤ n, m ≤ 30,q ≤ 10;

对于 100%的数据,1 ≤ n, m ≤ 30,q ≤ 500。

这题我只想到60分解法了。。

正解还是好机智,要注意500个q其实都是在同一个图上面的【想想这个有什么用就好了ORZ。。

copy题解:

编辑人:TsReaper 更新时间2015-08-18 14:48


考验状态记录技巧的一道好题!因为我们只要考虑指定块的位置,而指定块位置的移动和空白块有关,我们可以记录(x1,y1,x2,y2)表示指定块在(x1,y1),空白块在(x2,y2)的状态。由于空白块可以四方向移动,所以每个状态会向四个状态连边。这样共有(nm)^2个状态,总复杂度为O(q(nm)^2),只能通过60%的数据。

但是我们可以发现:只有空白块位于指定块的四方向上,指定块才可以移动。所以,我们可以记(x1,y1,dir)表示指定块在(x1,y1),空白块在指定块的dir方向(0表示上,1表示下什么的......)的状态。这样状态只有4nm个。

接下来我们考虑各个状态之间的连边。首先,空白块和指定块可以交换位置,这两个状态连边的边权为1;其次,假定空白块在指定块上方,空白块可以通过若干步移动来到空白块下/左/右方。这些状态连边的边权我们可以通过BFS计算出来。

这样就构造出了一张图,先把空白块移动到目标块旁边,之后向目标状态(空白块可以位于指定块的四个方向)做最短路即可。用spfa复杂度为O(qknm),可以通过100%的数据。

题解2:

这道题相当的坑,谁会想到NOIP最后一道题会考宽搜。(我一开始想成双连通分量了。。。)

宽搜。

可以发现,棋子要移动的前提是:它的四周有一个空格。因此状态总共只有2种决策:要么棋子与空格交换,要么空格在棋子周围的四个格子中自由移动。宽搜写起来也很方便。

那么现在问题来了,一组数据有多组询问,普通的宽搜是肯定要超时的,怎么办呢?

仔细一看就会发现这道题的特点:所有的询问都是在同一张图上进行的,而这张图又很小(30*30)。所以我们可以先预处理出所有点周围的空格在不经过它的情况下互相能够到达的最短路,这样每一次宽搜就相当于跑一次最短路了。(当然用SPFA最方便啊)

转自:http://blog.csdn.net/u013517878/article/details/40085405

结合起来就完全明白了ORZ。。。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
#define Maxn 35
#define INF 0xfffffff int mymin(int x,int y) {return x<y?x:y;} int a[Maxn][Maxn];
int n,m,qs; int bx[]={,,-,},
by[]={-,,,}; queue<int > q;
int d[Maxn*Maxn*];
int bfs(int x,int y,int xx,int yy)
{
while(!q.empty()) q.pop();
memset(d,-,sizeof(d));
q.push((x-)*m+y);d[(x-)*m+y]=;
while(!q.empty())
{
int now=q.front(),nx,ny;
nx=now/m+;ny=now%m;if(ny==) ny=m,nx--;
if(nx==xx&&ny==yy) return d[now];
for(int i=;i<;i++) if(a[nx+bx[i]][ny+by[i]])
{
int nn=(nx+bx[i]-)*m+ny+by[i];
if(d[nn]==-)
{
d[nn]=d[now]+;
q.push(nn);
}
}
q.pop();
}
return -;
} int num[Maxn][Maxn][],cnt; struct node
{
int x,y,c,next;
}t[Maxn*Maxn*];int len;
int first[Maxn*Maxn*]; void ins(int x,int y,int c)
{
t[++len].x=x;t[len].y=y;t[len].c=c;
t[len].next=first[x];first[x]=len;
} void init()
{
scanf("%d%d%d",&n,&m,&qs);
memset(a,,sizeof(a));
cnt=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
scanf("%d",&a[i][j]);
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) if(a[i][j])
for(int k=;k<;k++) if(a[i+bx[k]][j+by[k]])
{
num[i][j][k]=++cnt;
// printf("num_ %d %d %d = %d\n",i,j,k,num[i][j][k]);
}
len=;
memset(first,,sizeof(first));
int i,j;
for(i=;i<=n;i++) for(j=;j<=m;j++) if(a[i][j])
{
// printf("%d %d\n",i,j);
for(int k=;k<;k++) if(a[i+bx[k]][j+by[k]])
{
a[i][j]=;
for(int l=k+;l<;l++) if(a[i+bx[l]][j+by[l]])
{
int x=bfs(i+bx[k],j+by[k],i+bx[l],j+by[l]);
if(x==-) continue;
ins(num[i][j][k],num[i][j][l],x);
ins(num[i][j][l],num[i][j][k],x);
}
a[i][j]=;
ins(num[i][j][k],num[i+bx[k]][j+by[k]][-k],);
ins(num[i+bx[k]][j+by[k]][-k],num[i][j][k],);
}
}
/*for(int i=1;i<=len;i+=2)
{
printf("%d -> %d = %d\n",t[i].x,t[i].y,t[i].c);
}*/
} int ex,ey,sx,sy,tx,ty;
bool pp[Maxn*Maxn*],inq[Maxn*Maxn*];
int dis[Maxn*Maxn*]; int spfa(int st)
{
while(!q.empty()) q.pop();
memset(dis,,sizeof(dis));
memset(inq,,sizeof(inq));
q.push(st);dis[st]=;inq[st]=;
int ans=INF;
while(!q.empty())
{
int x=q.front();
if(!pp[x])
{
for(int i=first[x];i;i=t[i].next)
{
int y=t[i].y;
if(dis[y]>dis[x]+t[i].c)
{
dis[y]=dis[x]+t[i].c;
if(!inq[y])
{
inq[y]=;
q.push(y);
}
}
}
}
else ans=mymin(ans,dis[x]);
q.pop();inq[x]=;
}
return ans;
} void ffind()
{
memset(pp,,sizeof(pp));
for(int i=;i<=qs;i++)
{
int ans=INF;
scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
if(sx==tx&&sy==ty) printf("0\n");
else
{
for(int j=;j<;j++) pp[num[tx][ty][j]]=;
a[sx][sy]=;
for(int j=;j<;j++) if(a[sx+bx[j]][sy+by[j]])
{
int x=bfs(ex,ey,sx+bx[j],sy+by[j]);
// printf("%d %d %d = %d \n",sx,sy,j,x);
if(x==-) continue;
x+=spfa(num[sx][sy][j]);
// printf("%d %d %d = %d \n",sx,sy,j,x);
ans=mymin(ans,x);
}
a[sx][sy]=;
if(ans==INF) printf("-1\n");
else printf("%d\n",ans);
for(int j=;j<;j++) pp[num[tx][ty][j]]=;
} }
} int main()
{
init();
ffind();
return ;
}

注意一开始就在终点的特判【我被坑了ORZ....

放个数据,答案是377

2016-11-16 09:38:27

【NOIP 2013 DAY2 T3】 华容道(spfa)的更多相关文章

  1. NOIP 2013 day2

    tags: 模拟 贪心 搜索 动态规划 categories: 信息学竞赛 总结 积木大赛 花匠 华容道 积木大赛 Solution 发现如果一段先单调上升然后在单调下降, 那么这一块的代价是最高的减 ...

  2. 【NOIP 2015 DAY2 T3】 运输计划 (树链剖分-LCA)

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...

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

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

  4. 【NOIP 2017】Day2 T3 列队

    Problem Description \(Sylvia\) 是一个热爱学习的女孩子. 前段时间,\(Sylvia\) 参加了学校的军训.众所周知,军训的时候需要站方阵. \(Sylvia\) 所在的 ...

  5. Noip 2013 真题练习

    Day1 T1 转圈游戏 Link 一句话题意: 让你求 \({x + m \times 10^k} \bmod n\) 的结果. 直接套上快速幂的板子. code #include<iostr ...

  6. NOIP 2013 货车运输【Kruskal + 树链剖分 + 线段树 】【倍增】

    NOIP 2013 货车运输[树链剖分] 树链剖分 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在 ...

  7. [Noip 2013 Day1-3] 货车运输 做法总结

    [Noip 2013 Day1-3] 货车运输 做法总结 Online Judge:Luogu-1967 Label:启发式合并,离线,整体二分,按秩合并,倍增,最大生成树 打模拟离线赛时做到,顺便总 ...

  8. 一道搜索题【2013 noip提高组 DAY2 t3】华容道

    这篇不多说,具体的解释都在程序里 题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果 ...

  9. 【CodeVS 3290】【NOIP 2013】华容道

    http://codevs.cn/problem/3290/ 据说2013年的noip非常难,但Purpleslz学长还是AK了.能A掉这道题真心orz. 设状态$(i,j,k)$表示目标棋子在$(i ...

随机推荐

  1. C#根据WSDL文件生成WebService服务端代码

    转自:http://www.cnblogs.com/liyi93/archive/2012/01/30/2332320.html 虽然现在已经进入了.NET FrameWork 4.0的时代,WebS ...

  2. C#JSON格式数据的转换

    json格式字符串转化为json对象:JObject calculate = (JObject)JsonConvert.DeserializeObject(Rep.Request["data ...

  3. (LightOJ 1149) Factors and Multiples

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1149 Description You will be given two sets o ...

  4. Linux启动提示“unexpected inconsistency;RUN fsck MANUALLY”

    问题:在开机启动时,提示“unexpected inconsistency;RUN fsck MANUALLY”进不了系统 解决方法: fsck不仅可以对文件系统进行扫描,还能修正文件系统的一些问题, ...

  5. 计算序列中第k小的数

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4046399.html 使用分治算法,首先选择随机选择轴值pivot,并使的序列中比pivot ...

  6. el-get

    el-get Table of Contents 1. 依赖 2. 安装 3. 配置 3.1. 自定义包配置 4. 命令 5. 管理扩展 el-get 是一个emacs下的扩展管理工具.就像apt-g ...

  7. GroupBox 重绘圆角边框和文字

    private void GroupBox_Paint(object sender, PaintEventArgs e) { if (sender != null && sender ...

  8. iOS之内存管理浅谈

    1.何为ARC ARC是automatic reference counting自动引用计数,在程序编译时自动加入retain/release.在对象被创建时retain count+1,在对象被re ...

  9. FolderBrowserDialog(文件夹浏览对话框)

    1.选择数据库目录,在此处不需要新建文件夹,因此屏蔽新建文件夹按钮. C#代码 FolderBrowserDialog df = new FolderBrowserDialog(); //设置文件浏览 ...

  10. 在VS中手工创建一个最简单的WPF程序

    如果不用VS的WPF项目模板,如何手工创建一个WPF程序呢?我们来模仿WPF模板,创建一个最简单的WPF程序. 第一步:文件——新建——项目——空项目,创建一个空项目. 第二步:添加引用,Presen ...