NOIP2014华容道
说起来这道题还挺有难度的,我用了两个小时才把它AC,要是在赛场上的话。。。。这种题就果断放弃了
下面步入正题
小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。
小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:
给定一个棋盘,游戏可以玩 q 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 i 次玩的时候,空白的格子在第 EX_i 行第 EY_i 列,指定的可移动棋子的初始位置为第 SX_i 行第 SY_i 列,目标位置为第 TX_i 行第 TY_i 列。
假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。
第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n、m 和 q;
接下来的 n 行描述一个 n*m 的棋盘,每行有 m 个整数,每两个整数之间用一个空格隔开,每个整数描述棋盘上一个格子的状态,0 表示该格子上的棋子是固定的,1 表示该格子上的棋子可以移动或者该格子是空白的。
接下来的 q 行,每行包含 6 个整数依次是 EX_i、EY_i、SX_i、SY_i、TX_i、TY_i,每两个整数之间用一个空格隔开,表示每次游戏空白格子的位置,指定棋子的初始位置和目标位置。
输出有 q 行,每行包含 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
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。
很明确的是要想把格子S移到目标位置T,首先得把白格子E移到S的旁边,在通过一系列的操作使格子S到达T
格子S想要走到与它相邻的k方向(left,right,up,down)上的格子,必须先把E格子通过w的花费移到那里,然后在用1的花费使S走到那 里,总花费为w+1,由于从一个格子向相邻方向上走一步的花费要多次使用,因此我们把它预处理成数组move[x][y][k][h],表示从(x,y)这个棋子,白格子在k方向上,使棋子走到h方向上相邻的格子的最少花费,这个可以用BFS预处理
有了这么多东西,能不能用BFS做呢?不行。从一个点走到相邻的节点的花费不一定是1,而且还受白格子所在方向的影响,所以就不再设状态为(x,y),而是(x,y,k),k表示白格子的方向,dist[x][y][k]存储走到这个状态的最小步数。很明显,从一个格子向h方向走的最小代价就是move[x][y][k][h],很明显这个状态只能转移到(x,y,other(h)),other(h)表示和h相反的方向,比如你向右走完一次,白格子一定在这个格子的左侧。
现在已经构建了一个又状态(x,y,k)构成的一张图,边权也已经算出来了,因此想要从出发点找一条到结束点的最短路径,可以用SPFA或堆Dijkstra,我更喜欢SPFA,因为一开始你要让四个状态入队,SFPA更方便一些,事实证明还是很快的
测试点#puzzle1.in 结果:AC 内存使用量: 364kB 时间使用量: 1ms
测试点#puzzle10.in 结果:AC 内存使用量: 616kB 时间使用量: 0ms
测试点#puzzle11.in 结果:AC 内存使用量: 1004kB 时间使用量: 2ms
测试点#puzzle12.in 结果:AC 内存使用量: 1384kB 时间使用量: 7ms
测试点#puzzle13.in 结果:AC 内存使用量: 2024kB 时间使用量: 11ms
测试点#puzzle14.in 结果:AC 内存使用量: 2536kB 时间使用量: 28ms
测试点#puzzle15.in 结果:AC 内存使用量: 3052kB 时间使用量: 48ms
测试点#puzzle16.in 结果:AC 内存使用量: 3048kB 时间使用量: 52ms
测试点#puzzle17.in 结果:AC 内存使用量: 2028kB 时间使用量: 11ms
测试点#puzzle18.in 结果:AC 内存使用量: 2540kB 时间使用量: 27ms
测试点#puzzle19.in 结果:AC 内存使用量: 3052kB 时间使用量: 51ms
测试点#puzzle2.in 结果:AC 内存使用量: 492kB 时间使用量: 0ms
测试点#puzzle20.in 结果:AC 内存使用量: 2924kB 时间使用量: 50ms
测试点#puzzle3.in 结果:AC 内存使用量: 488kB 时间使用量: 1ms
测试点#puzzle4.in 结果:AC 内存使用量: 364kB 时间使用量: 1ms
测试点#puzzle5.in 结果:AC 内存使用量: 492kB 时间使用量: 0ms
测试点#puzzle6.in 结果:AC 内存使用量: 492kB 时间使用量: 0ms
测试点#puzzle7.in 结果:AC 内存使用量: 616kB 时间使用量: 1ms
测试点#puzzle8.in 结果:AC 内存使用量: 876kB 时间使用量: 4ms
测试点#puzzle9.in 结果:AC 内存使用量: 1388kB 时间使用量: 8ms
#include
#include
#include
#include
#define up 1
#define down 2
#define left 3
#define right 4
#define maxn 35
#define inf 0x3f3f3f3f
using namespace std;
struct node
{
int x, y, k;
}t1, t2;
int pan[maxn][maxn], dist[maxn][maxn][5], Ex, Ey, move[maxn][maxn][5][5], deep[maxn][maxn], n, m;
bool in[maxn][maxn][5], done[maxn][maxn];
queue q, qb;
inline int other(int k)
{
if(k==up)return down;
if(k==down)return up;
if(k==left)return right;
if(k==right)return left;
}
node go(node n, int k)
{
node t=n;
if(k==up)t.x--;
if(k==down)t.x++;
if(k==left)t.y--;
if(k==right)t.y++;
return t;
}
int bfs(const node s, const node t)
{
if(pan[s.x][s.y]==0 || pan[s.x][s.y]==0)return inf;
memset(deep,0x3f,sizeof(deep));
memset(done,0,sizeof(done));
qb=*(new queue);
int i, j, k, h;
node now, tmp;
qb.push(s);
deep[s.x][s.y]=0;
done[s.x][s.y]=true;
while(!qb.empty() && !done[t.x][t.y])
{
now=qb.front();
qb.pop();
for(k=1;k<=4;k++)
{
tmp=go(now,k);
if(!done[tmp.x][tmp.y] && pan[tmp.x][tmp.y]==1)
{
done[tmp.x][tmp.y]=true;
qb.push(tmp);
deep[tmp.x][tmp.y] = deep[now.x][now.y]+1;
}
}
}
return deep[t.x][t.y];
}
void init() //初始化move数组
{
memset(move,0x3f,sizeof(move));
int i, j, k, h;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
if(pan[i][j]==0)continue;
pan[i][j]=0;
for(k=1;k<=4;k++)
{
for(h=1;h<=4;h++)
{
if(h);
for(k=1;k<=4;k++)
{
t=(node){S.x,S.y,k};
q.push(t), in[S.x][S.y][k]=true;
dist[S.x][S.y][k]=bfs((node){Ex,Ey},go(S,k));
}
pan[S.x][S.y]=1;
while(!q.empty())
{
now=q.front();
q.pop();
in[now.x][now.y][now.k]=false;
for(h=1;h<=4;h++)
{
t=go(now,h);
t.k=other(h);
if(dist[now.x][now.y][now.k] + move[now.x][now.y][now.k][h] < dist[t.x][t.y][other(h)])
{
dist[t.x][t.y][other(h)]=dist[now.x][now.y][now.k]+move[now.x][now.y][now.k][h];
if(!in[t.x][t.y][t.k])
q.push(t), in[t.x][t.y][t.k]=true;
}
}
}
ans=inf;
for(k=1;k<=4;k++)
ans = min(ans,dist[T.x][T.y][k]);
return ans;
}
int main()
{
int q, sx, sy, tx, ty, i, j, k, ans;
scanf("%d%d%d",&n,&m,&q);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&pan[i][j]);
init();
for(i=1;i<=q;i++)
{
scanf("%d%d%d%d%d%d",&Ex,&Ey,&sx,&sy,&tx,&ty);
ans=spfa((node){sx,sy},(node){tx,ty});
if(ans