题目:http://poj.org/problem?id=1198
AC代码(C++):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define INF0 0x7fffffff
#define eps 1e-5
typedef unsigned long long ull;
typedef long long ll;
using namespace std;
struct NODE {
int x[4], y[4];
int step;
};
NODE s, e;
int vis[300][300];
int dir[4][2] = { { 1,0 },{ -1,0 },{ 0,1 },{ 0,-1 } };
bool ans;
void toVis(int &x, int &y, int *xx, int *yy) {
x = 0;
y = 0;
for (int i = 0; i < 4; i++) {
x |= 1 << (xx[i] - 1);
y |= 1 << (yy[i] - 1);
}
}
void bfs(NODE s, char flag) {
queue<NODE> q;
int tmpx, tmpy;
toVis(tmpx, tmpy, s.x, s.y);
if (flag == 2 && vis[tmpx][tmpy] == 1) {
ans = true;
return;
}
vis[tmpx][tmpy] = flag;
q.push(s);
NODE node, tmp;
while (!q.empty()) {
node = q.front();
q.pop();
if (node.step == 4)return;
for (int i = 0; i < 4; i++) {//4个棋子
for (int j = 0; j < 4; j++) {//4个方向
tmp = node;
tmp.x[i] += dir[j][0];
tmp.y[i] += dir[j][1];
if (tmp.x[i] <= 0 || tmp.x[i] > 8 || tmp.y[i] <= 0 || tmp.y[i] > 8)continue;
int k = 0;
for (; k < 4; k++) {
if (i == k)continue;
if (tmp.x[i] == tmp.x[k] && tmp.y[i] == tmp.y[k])break;
}
if (k != 4) {
tmp.x[i] += dir[j][0];
tmp.y[i] += dir[j][1];
if (tmp.x[i] <= 0 || tmp.x[i] > 8 || tmp.y[i] <= 0 || tmp.y[i] > 8)continue;
k = 0;
for (; k < 4; k++) {
if (i == k)continue;
if (tmp.x[i] == tmp.x[k] && tmp.y[i] == tmp.y[k])break;
}
if (k != 4)continue;
}
toVis(tmpx, tmpy, tmp.x, tmp.y);
if (vis[tmpx][tmpy] == flag)continue;
else if (vis[tmpx][tmpy] == 1 && flag == 2) {
ans = true;
return;
}
vis[tmpx][tmpy] = flag;
tmp.step++;
q.push(tmp);
}
}
}
}
int main() {
while (cin >> s.x[0] >> s.y[0] >> s.x[1] >> s.y[1] >> s.x[2] >> s.y[2] >> s.x[3] >> s.y[3]) {
cin >> e.x[0] >> e.y[0] >> e.x[1] >> e.y[1] >> e.x[2] >> e.y[2] >> e.x[3] >> e.y[3];
s.step = 0;
e.step = 0;
memset(vis, 0, sizeof(vis));
ans = false;
bfs(s, 1);
bfs(e, 2);
if (ans)cout << "YES\n";
else cout << "NO\n";
}
//system("pause");
}
总结: 搜索, 双向BFS+状态压缩. 这段代码只需要624K内存和32ms时间就过了, 神搜索. 一般来说, 用BFS来搜索都要保存大量状态, 与DFS相比基本上是用空间换取时间. 首先这道题的规模是(4个棋子*4个方向)^8步, 即16^8, 朴素的搜索从时间上来看是不可行的. 所以我们从起点和终点分别搜索, 每边只搜4步, 规模降为2*(4*4)^4, 直接降了好几个数量级. 编程实现上只需要从起点开始搜4步, 然后从终点开始搜, 发现搜到了vis被从起点搜索标记的状态说明找到了这条路径. 问题是要怎么表示这个棋盘状态来用vis标记? 因为棋盘是8*8, 根据行号和列号就能唯一确定一个点, 所以我们把行和列压缩成两个8位的bit串, 在有棋子的坐标标上1, 其余为0. 例如输入数据中的状态4 4 4 5 5 4 6 5, 有棋子的行号为4, 5和6, 有棋子的列号为4和5, 那么行bit串为00011100, 列bit串为00011000, 分别用整数表示为28和24. 因为8位整数最大为2^8-1=255, 所以只需要用vis[300][300]的二维数组就能表示, 不仅占内存小, 还快.