POJ 1198 Solitaire (双向广搜)

题目类型  双向广搜

题目意思
有一个 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值