【NOIP 2013 DAY2 T3】 华容道(spfa)
题目描述
【问题描述】
小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间。
小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:
在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的;
有些棋子是固定的,有些棋子则是可以移动的;
- 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。
游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。
给定一个棋盘,游戏可以玩 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说明
【输入输出样例说明】
棋盘上划叉的格子是固定的,红色格子是目标位置,圆圈表示棋子,其中绿色圆圈表示目标棋子。
- 第一次游戏,空白格子的初始位置是 (3, 2)(图中空白所示),游戏的目标是将初始位置在(1, 2)上的棋子(图中绿色圆圈所代表的棋子)移动到目标位置(2, 2)(图中红色的格子)上。
移动过程如下:
- 第二次游戏,空白格子的初始位置是(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最方便啊)
结合起来就完全明白了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)的更多相关文章
- NOIP 2013 day2
tags: 模拟 贪心 搜索 动态规划 categories: 信息学竞赛 总结 积木大赛 花匠 华容道 积木大赛 Solution 发现如果一段先单调上升然后在单调下降, 那么这一块的代价是最高的减 ...
- 【NOIP 2015 DAY2 T3】 运输计划 (树链剖分-LCA)
题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...
- Luogu 1979 NOIP 2013 华容道(搜索,最短路径)
Luogu 1979 NOIP 2013 华容道(搜索,最短路径) Description 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面 ...
- 【NOIP 2017】Day2 T3 列队
Problem Description \(Sylvia\) 是一个热爱学习的女孩子. 前段时间,\(Sylvia\) 参加了学校的军训.众所周知,军训的时候需要站方阵. \(Sylvia\) 所在的 ...
- Noip 2013 真题练习
Day1 T1 转圈游戏 Link 一句话题意: 让你求 \({x + m \times 10^k} \bmod n\) 的结果. 直接套上快速幂的板子. code #include<iostr ...
- NOIP 2013 货车运输【Kruskal + 树链剖分 + 线段树 】【倍增】
NOIP 2013 货车运输[树链剖分] 树链剖分 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在 ...
- [Noip 2013 Day1-3] 货车运输 做法总结
[Noip 2013 Day1-3] 货车运输 做法总结 Online Judge:Luogu-1967 Label:启发式合并,离线,整体二分,按秩合并,倍增,最大生成树 打模拟离线赛时做到,顺便总 ...
- 一道搜索题【2013 noip提高组 DAY2 t3】华容道
这篇不多说,具体的解释都在程序里 题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果 ...
- 【CodeVS 3290】【NOIP 2013】华容道
http://codevs.cn/problem/3290/ 据说2013年的noip非常难,但Purpleslz学长还是AK了.能A掉这道题真心orz. 设状态$(i,j,k)$表示目标棋子在$(i ...
随机推荐
- oracle添加表字段跟修改表字段属性
添加字段 alter table mid_contactinfo add(status varchar(20),createdate varchar(50),modifydate varchar(50 ...
- JSP编程中常用的JavaScript技术(转载)
1.<tronMouseOver=this.style.backgroundColor=’#FFFFFF’ onMouseOut=this.style.backgroundColor=”> ...
- ZOJ 1122 Clock(模拟)
Clock Time Limit: 2 Seconds Memory Limit: 65536 KB You are given a standard 12-hour clock with ...
- 如何在Markdown、HTML编辑器上输入一些特殊字符
如何输入EntityCode 参考: 1.EntityCode 2.Common HTML entities used for typography 3.Latin Supplement-拉丁补充
- KMP的模版实现(以hdu1711为例)
贴代码,觉得带template的有一些大材小用……不过还是按自己风格写吧! /************************************************************* ...
- svn 钩子 post-commit 出现255错误解决办法
首先检查代码中是否有可执行命令 #!/bin/sh 然后 检查post-commit权限 post-commit 脚本文件的权限不对,post-commit 脚本必须有 +x 权限. chown sv ...
- 不同的extend 在调用构造函数时不同的写法
/** * jQuery.hhNewSilder 滚动图片插件 * User: huanhuan * QQ: 651471385 * Email: th.wanghuan@gmail.com ...
- Memcache存储大数据的问题
Memcached存储单个item最大数据是在1MB内,假设数据超过1M,存取set和get是都是返回false,并且引起性能的问题. 我们之前对排行榜的数据进行缓存,因为排行榜在我们全部sql se ...
- 使用python抓取有路网图书信息(原创)
以前挺喜欢去有路网买二手书的,但是有路网有个缺陷,就是放在图书列表中的书很多都没货了,尤其是一些热门的方向,比如android,在列表中的书大多都没有货了,你必须一个一个点进入查看详细信息才能得知图书 ...
- 拓展:switch实现
拓展:switch实现 参考中谷教育 python视频:switch switch语句用于编写多分支结构的程序,类似于if ... elif ...else语句.switch语句表达的分支结构比if ...

