【题目链接】
CodeVS 3290 华容道 [NOIP 2013] COGS 1442 华容道 [NOIP 2013]
【题目描述】
小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次。于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间。 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的:
在一个 $n*m$ 棋盘上有 $n*m$ 个格子,其中有且只有一个格子是空白的,其余 $n*m-1$个格子上每个格子上有一个棋子,每个棋子的大小都是 $1*1$ 的; 有些棋子是固定的,有些棋子则是可以移动的; 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。 游戏的目的是把某个指定位置可以活动的棋子移动到目标位置。 给定一个棋盘,游戏可以玩 $q$ 次,当然,每次棋盘上固定的格子是不会变的,但是棋盘上空白的格子的初始位置、指定的可移动的棋子的初始位置和目标位置却可能不同。第 $i$ 次玩的时候,空白的格子在第 $EX_i$ 行第 $EY_i$ 列,指定的可移动棋子的初始位置为第 $SX_i$ 行第 $SY_i$ 列,目标位置为第 $TX_i$ 行第 $TY_i$ 列。 假设小 B 每秒钟能进行一次移动棋子的操作,而其他操作的时间都可以忽略不计。请你告诉小 B 每一次游戏所需要的最少时间,或者告诉他不可能完成游戏。
【解题思路】
首先声明本文不是正解哈,而只是前60分的直接搜索做法。是因为最近在学习搜索嘛,只是拿来练手而已,正解的话自行Google啦。
本题的直接搜索性价比很高~~(性价比高 == 水)~~,可以拿到至少60分。首先显然是BFS,怎样定义状态呢,我们注意到,任何时刻我们都只关心目标棋子和空白格子的位置,其他的棋子对我们来说都是一样的,我们并不关心其位置。所以我们以目标棋子和空白格子的坐标组成状态 (x, y, spaceX, spaceY),判重的话,数组就够了。然后,开搜吧!
【80分代码】
可能是数据弱,也可能是代码常数小,反正莫名其妙过了80分啦。
#include <cstdio>
#include <queue>
#include <cstring>
#define MAXM 40
#define MAXN 40
const int dx[] = { 0, 0, 1, -1 };
const int dy[] = { 1, -1, 0, 0 };
struct Node{
int x, y;
int spaceX, spaceY;
int step;
Node() {}
Node(int x, int y, int spaceX, int spaceY, int step) : x(x), y(y), spaceX(spaceX), spaceY(spaceY), step(step) {}
};
int m, n, q;
int G[MAXM][MAXN];
bool vis[MAXM][MAXN][MAXM][MAXN];
Node S, T;
inline void readData(){
scanf("%d %d %d %d %d %d", &S.spaceX, &S.spaceY, &S.x, &S.y, &T.x, &T.y);
S.spaceX--, S.spaceY--, S.x--, S.y--, T.x--, T.y--; // 习惯下标从0开始啦
}
inline bool judge(int x, int y, int sX, int sY){
if(x < 0 || x >= m || y < 0 || y >= n || !G[x][y] || !G[sX][sY]) return false;
if(vis[x][y][sX][sY]) return false;
else vis[x][y][sX][sY] = true;
return true;
}
inline int BFS(){
if(S.x == T.x && S.y == T.y) return 0;
memset(vis, 0, sizeof vis);
std::queue<Node> Q;
S.step = 0;
vis[S.x][S.y][S.spaceX][S.spaceY] = true;
Q.push(S);
while(!Q.empty()){
Node &v = Q.front(); // 声明引用可以不发生结构体的复制
for(int k = 0; k < 4; k++){
int xi = v.x, yi = v.y;
int sX = v.spaceX + dx[k], sY = v.spaceY + dy[k];
if(xi == sX && yi == sY) xi = v.spaceX, yi = v.spaceY;
if(judge(xi, yi, sX, sY)){
if(xi == T.x && yi == T.y) return v.step + 1;
else Q.push(Node(xi, yi, sX, sY, v.step + 1));
}
}
Q.pop();
}
return -1;
}
int main(){
// freopen("PuzzleNOIP2013.in", "r", stdin), freopen("PuzzleNOIP2013.out", "w", stdout);
scanf("%d%d%d", &m, &n, &q);
for(int i = 0; i < m; i++) for(int j = 0; j < n; j++) scanf("%d", G[i] + j);
for(int i = 0; i < q; i++){
readData();
printf("%d\n", BFS());
}
// fclose(stdin), fclose(stdout);
return 0;
}
就这样啦。