【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 ...
 
随机推荐
- asp下实现多条件模糊查询SQL语句
			
常写一个简单的模糊查询的SQL语句格式可以如下例: sql="select * from 表名 where 字段名 like ’%" & request.form(&quo ...
 - asp.net中常用的几种身份验证方式
			
转载:http://www.cnblogs.com/dinglang/archive/2012/06/03/2532664.html 前言 在B/S系统开发中,经常需要使用"身份验证&q ...
 - poj2337  欧拉路径
			
poj2337 这道题昨天晚上开始做,今天才A.但是问题想透了, 发现其实没那么难 题目大意: 给你一些单词,如果一个单词的末尾字符与另一个单词首字符相同,则两个的单词可以连接.问是否可以把所有单词连 ...
 - android webview乱码问题
			
使用 loadData方法是中文部分会出现乱码,即使指定“utf-8”.“gbk”.“gb2312”也一样. webView.getSettings().setDefaultTextEncodingN ...
 - CefSharp开源库的使用(一)
			
关于CEF: 嵌入式Chromium框架(简称CEF) 是一个由Marshall Greenblatt在2008建立的开源项目,它主要目的是开发一个基于Google Chromium的Webbrows ...
 - 查看帮助文档的一些方法:help,dir,type,func_global等
			
help与dir与type:在使用python来编写代码时,会经常使用python自带函数或模块,一些不常用的函数或是模块的用途不是很清楚,这时候就需要用到help函数来查看帮助.这里要注意下,hel ...
 - Android Metro风格的Launcher开发系列第一篇
			
前言:从毕业到现在已经三年多了,回忆一下这三年基本上没有写过博客,总是觉得忙,没时间写,也觉得写博客没什么大用.但是看到很多大牛们都在写博客,分享自己的东西,所以嘛本着向大牛看齐,分享第一,记录第二的 ...
 - ubuntu tab命令补全失效
			
主要是由于环境变量设置出了问题,修改/etc/environment即可. sudo nano /etc/environment 修改后source /etc/environment
 - CSS多行文字截断
			
有时候容器的宽度是固定的,但要显示的文字有点多,就需要将多余的文字隐藏,而且为了表示还有字没有显示,用省略号表示. 类似这样: 单行文字 单行文字截断比较明显: .truncate { width: ...
 - ZOJ 3211 Dream City(DP)
			
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3374 题目大意:JAVAMAN 到梦幻城市旅游见到了黄金树,黄金树上 ...
 
			
		
