枚举(BFS+矩阵压缩):【POJ-1753】&&【POJ-2965】

POJ-1753 Flip Game(棋盘反转:BFS+状态压缩)
链接:http://poj.org/problem?id=1753
  题目:通过翻转将4*4的棋盘转换为同一颜色
  解题关键:当我们使用0或者1两种状态来表示棋子的黑色或者白色时,方格就可以被转化成一个16位的二进制状态数(用一个int32位就可以表示),而游戏完成正好对应这个数为0或者65535的状态。用位运算来模拟情况。
  改进:针对棋盘较大的情况,采用最优解的情况。按照从上往下搜索的思路来进行,那么每一行的棋子翻转只会影响到上一行的棋子颜色。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;

bool visit[65540]; //记录每种情况是否已经出现,防止再次出现
int steps[65540];//用来记录steps
int exclusive(int state,int i) {
	state ^= 1 << i;
	if (i % 4 != 0) state ^= 1 << (i - 1);
	if (i % 4 != 3) state ^= 1 << (i + 1);
	if (i + 4 < 16) state ^= 1 << (i + 4);
	if (i - 4 >= 0) state ^= 1 << (i - 4);
	return state;
}

int BFS(int start) {
	queue<int> q;
	q.push(start);
	visit[start] = 0;
	steps[start] = 0;
	while (!q.empty()) {
		int now = q.front();
		q.pop();
		if (now == 0 || now==65535) {
			return steps[now];
		}
		for (int i = 0; i < 16; i++) {
			int state = exclusive(now, i);
			if (visit[state] == 0) {
				q.push(state);
				visit[state] = 1;
				steps[state] = steps[now] + 1;
			}
		}
	}
	return -1;
}

int main() {
	memset(visit, false, sizeof(visit));//初始化
	memset(steps, 0, sizeof(steps));
	int state = 0;
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			state <<= 1;
			char t;
			scanf("%c", &t);
			if (t == 'b') 
				state |= 1;
			else 
				state |= 0;
		}
		getchar();
	}
	int res = BFS(state);
	if (res == -1) {
		printf("Impossible\n");
	}else {
		printf("%d\n", res);
	}
	return 0;
}

类似的题目【POJ-2965】开关:不同的地方在于每次变换是以行、列为一组,最终的状态只有一种。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<queue>
using namespace std;

bool visit[65540];
int steps[65540];
int make[65540];
int front[65540];
queue<int> q;
int change(int state, int i) {
	int row = i / 4;
	int col = i % 4;
	//行
	for (int j = 0; j < 4; j++) {
		state ^= (1 << (row * 4 + j));
	}
	//列
	for (int j = 0; j < 4; j++) {
		state ^= (1 << (j * 4 + col));
	}
	//自身
	state ^= (1 << i);
	return state;
}
int BFS() {
	while (!q.empty()) {
		int now = q.front();
		q.pop();
		if (now == 0) {
			return steps[now];
		}
		for (int i = 0; i < 16; i++) {
			int next=change(now,i);
			if (visit[next] == 0) {
				visit[next] = 1;
				q.push(next);
				steps[next] = steps[now] + 1;
				front[next] = now;
				make[next] = i;
			}
		}
	}
}

int main() {
	int state = 0;
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 4; j++) {
			char t;
			state <<= 1;
			scanf("%c", &t);
			if (t == '+') {
				state |= 1;
			}else {
				state |= 0;
			}	
		}
		getchar();
	}
	memset(visit, 0, sizeof(visit));
	memset(steps, 0, sizeof(steps));
	memset(front, -1, sizeof(steps));
	q.push(state);
	visit[state] = true;
	steps[state] = 0;
	printf("%d\n",BFS());
	state = 0;
	while (front[state] != -1) {
		int i=make[state];
		printf("%d %d\n", 4 - i / 4, 4 - i % 4);
		state = front[state];
	}
	return 0;
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值