题目类型 双向广搜
题目意思
有一个 8 × 8的棋盘
棋盘上有 4 个棋子 现在给出一个初态 和 一个终态 问能不能在 8 步内从初态 转换到 终态
每一步可以移动一粒棋子 棋子每一步只能向上 下 左 右 其中一个方向移一格 当目标位置已经有棋子时可以跳一格即现在棋子在(3,3)但(3,2)已经有棋子了那么(3,3)可以跳到(3,1)那格去, 同时要求(3,1)不能有棋子
解题方法
首先计算一下时间复杂度 有4个棋子 每个棋子的可能最大转移情况是4个 即 一步可能有16 个可转移状态 那么 8 步就是 16 ^ 8 即 (2^4)^8即 2^32
直接BFS会超时那么可以用双向广搜的方法 即从初态 BFS 4步 从终态也 BFS 4 步 那么如果两个目标状态集有交集说明有可行解
为什么划分成两个4步是可行的呢 ? 因为如果你找到一个方法是 从初态走 6 步 从终态走2步然后相等的话, 其实就相当于从终态走2步后再顺着初态的第5和第6步的逆向走即可走到初态走4步走到的地方
参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
using namespace std;
bool ans;
typedef unsigned long long LL;
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
struct Node {
LL x; int time;
};
set<LL>S1;
set<LL>S2;
LL ttt;
void BFS(LL x, int flag) {
Node tmp; tmp.x = x, tmp.time = 0;
queue<Node>q;
q.push(tmp);
while(!q.empty()) {
Node f = q.front(); q.pop();
if(f.time == 4) continue;
for( int j=0; j<64; j++ ) {
if(f.x & (1LL<<j)) {
for( int i=0; i<4; i++ ) {
int tx = j/8+dx[i];
int ty = j%8+dy[i];
if(tx >= 0 && tx < 8 && ty >= 0 && ty < 8) {
if(f.x & (1LL<<(tx*8+ty))) {
tx += dx[i];
ty += dy[i];
if(tx >= 0 && tx < 8 && ty >= 0 && ty < 8) {
if((f.x & (1LL<<(tx*8+ty)))==0) {
LL tmp = f.x ^ (1LL<<j) | (1LL<<(tx*8+ty));
Node tt; tt.x = tmp; tt.time = f.time + 1;
if(flag) {
if(S1.find(tmp) != S1.end()) {
ans = true;
return ;
}
if(S2.find(tmp) == S2.end()) {
q.push(tt);
S2.insert(tmp);
}
}
else {
if(S1.find(tmp) == S1.end()) {
q.push(tt);
S1.insert(tmp);
}
}
}
}
}
else {
LL tmp = f.x ^ (1LL<<j) | (1LL<<(tx*8+ty));
Node tt; tt.x = tmp; tt.time = f.time + 1;
if(flag) {
if(S1.find(tmp) != S1.end()) {
ans = true;
return ;
}
if(S2.find(tmp) == S2.end()) {
q.push(tt);
S2.insert(tmp);
}
}
else {
if(S1.find(tmp) == S1.end()) {
q.push(tt);
S1.insert(tmp);
}
}
}
}
}
}
}
}
}
int main() {
//freopen("in", "r", stdin);
int r, c;
while(scanf("%d", &r) != EOF) {
S1.clear(), S2.clear();
scanf("%d", &c);
LL sta = 0, end = 0;
sta |= (1LL<<(8*(r-1)+c-1));
for( int i=0; i<6; i+=2 ) {
scanf("%d%d", &r, &c);
sta |= (1LL<<(8*(r-1)+c-1));
}
for( int i=0; i<8; i+=2 ) {
scanf("%d%d", &r, &c);
end |= (1LL<<(8*(r-1)+c-1));
}
ans = false;
BFS(sta, false);
BFS(end, true);
if(ans) printf("YES\n");
else printf("NO\n");
}
return 0;
}