POJ 1198.Solitaire

题目: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]的二维数组就能表示, 不仅占内存小, 还快.

你可能感兴趣的:(poj,acm,poj)