hdu1401 Solitaire
题目链接: hdu1401 Solitaire
这是一道十分适合双向广搜的题。
考虑到 \(4\) 个相同棋子在一个 \(8\times8\) 的棋盘上,总状态数不过 \(\C_{64}^4=635376<1e6\) 种,单向广搜应该也不会超时,不过我第一次试了下结果还是 \(TLE\) 了,猜想可能是使用 \(map\) 标记耗时的缘故,换成数组标记应该可以过吧。
下面是双向 \(BFS\) 的 \(AC\) 代码。
/**
* hdu1401 Solitaire
*
*/
#include <cstdio>
#include <queue>
#include <iostream>
#include <cstring>
#include <string>
#include <stack>
#include <vector>
#include <map>
#include <cstdlib>
#include <algorithm>
using namespace std;
int id(int *num)
{
int tmp[4];
for (int i = 0; i < 4; ++i) {
tmp[i] = num[2*i]*10+num[2*i+1];
}
sort(tmp, tmp+4);
int res = 0;
for (int i = 0; i < 4; ++i) res = res*100+tmp[i];
// for (int i = 0; i < 4; ++i) cout << tmp[i] << ' '; cout << endl;
return res;
}
int sid, eid;
struct node{int x, step;};
int dir[4][2] = {-1,0,1,0,0,-1,0,1}; // 上下左右
map<int, int> vis;
int bfs()
{
queue<node> Q;
Q.push(node{sid, 0});
vis[sid] = 1;
while (!Q.empty()) {
node t = Q.front(); Q.pop();
// cout << t.x << '#';
if (t.x == eid) return 1;
if (t.step == 4) continue; // 步数大于4的就不用入队了
int num[] = {t.x/1000000,t.x/10000%100,t.x/100%100,t.x%100};
for (int i = 0; i < 4; ++i) { // 分别处理4个piece
// cout << num[i] << ':' << endl;
int x = num[i]/10, y = num[i]%10;
for (int j = 0; j < 4; ++j) { // 遍历四个方向
int tx = x+dir[j][0];
int ty = y+dir[j][1]; // 这里开始不小心写成 ty=x+dir[j][1]
// 果然菜是有原因的
if (tx < 1 || tx > 8) continue;
if (ty < 1 || ty > 8) continue;
int n = tx*10+ty;
for (int k = 0; k < 4; ++k) if (n == num[k]) { // 有冲突则再移一格,相当于jump
tx += dir[j][0];
ty += dir[j][1];
break;
}
if (tx < 1 || tx > 8) continue;
if (ty < 1 || ty > 8) continue;
n = tx*10+ty;
if (n == num[0]) continue;
if (n == num[1]) continue;
if (n == num[2]) continue;
if (n == num[3]) continue;
int tmp[8];
for (int k = 0; k < 4; ++k) {
tmp[2*k] = num[k]/10;
tmp[2*k+1] = num[k]%10;
}
tmp[2*i] = tx, tmp[2*i+1] = ty;
int nid = id(tmp);
if (vis[nid]) continue;
Q.push(node{nid, t.step+1});
vis[nid] = 1;
}
// cout << endl;
}
// system("pause");
}
return 0;
}
int bfs2()
{
queue<node> Q;
Q.push(node{eid, 0});
vis[eid] = 2;
while (!Q.empty()) {
node t = Q.front(); Q.pop();
if (t.step == 4) continue; // 步数大于4的就不用入队了
int num[] = {t.x/1000000,t.x/10000%100,t.x/100%100,t.x%100};
for (int i = 0; i < 4; ++i) { // 分别处理4个piece
int x = num[i]/10, y = num[i]%10;
for (int j = 0; j < 4; ++j) { // 遍历四个方向
int tx = x+dir[j][0];
int ty = y+dir[j][1];
if (tx < 1 || tx > 8) continue;
if (ty < 1 || ty > 8) continue;
int n = tx*10+ty;
for (int k = 0; k < 4; ++k) if (n == num[k]) { // 有冲突则再移一格,相当于jump
tx += dir[j][0];
ty += dir[j][1];
break;
}
if (tx < 1 || tx > 8) continue;
if (ty < 1 || ty > 8) continue;
n = tx*10+ty;
if (n == num[0]) continue;
if (n == num[1]) continue;
if (n == num[2]) continue;
if (n == num[3]) continue;
int tmp[8];
for (int k = 0; k < 4; ++k) {
tmp[2*k] = num[k]/10;
tmp[2*k+1] = num[k]%10;
}
tmp[2*i] = tx, tmp[2*i+1] = ty;
int nid = id(tmp);
int tv = vis[nid];
if (tv == 2) continue;
else if (tv == 1) return 1;
Q.push(node{nid, t.step+1});
vis[nid] = 2;
}
}
}
return 0;
}
int main()
{
int s[8], e[8];
while (cin >> s[0]) {
for (int i = 1; i < 8; ++i) cin >> s[i];
for (int i = 0; i < 8; ++i) cin >> e[i];
sid = id(s), eid = id(e);
// cout << sid << ' ' << eid << endl;
vis.clear();
if (bfs()) puts("YES");
else puts(bfs2()?"YES":"NO");
}
return 0;
}

浙公网安备 33010602011771号