poj 1753 枚举+深搜

本文探讨了一个4x4矩阵的翻转问题,通过DFS和位操作两种方法寻找最少翻转次数使矩阵颜色统一。提供了清晰易懂的代码示例。

题意:给一个4*4的矩阵,每个格非黑即白。选择翻动其中一个格的时候,它的上下左右同时也要翻过去,问最少翻几次可以把矩阵变成一样的颜色。

思路:每个格最多翻动一次(不算翻动其它格时把它也翻过去的情况),这样最多执行同样的操作16次,就可以得出结论。

这是我看到的写得比较清晰的代码,模块功能紧凑,我写了注释。转自:http://blog.sina.com.cn/s/blog_6635898a0100ivzv.html

1753Accepted704K204MSG++1146B

#include <iostream>
using namespace std;

bool map[6][6], findaaa = false;//map存矩阵中格的颜色,findaaa代表是否找到结果
int step;//需要的步数
int dr[5] = {-1, 0, 0, 0, 1};//dr和dc合起来代表每一个格和它周围的格的相对位置
int dc[5] = {0, -1, 0, 1, 0};//分别为上(-1,0)、左(0,1)、中(自己)、右(0,1)、下(1,0)

bool isgoal() {
	for(int i = 1; i<=4; ++i)
	{
		for(int j = 1; j<=4; ++j)
		{
			if(map[i][j] != map[1][1])//判断矩阵中的其它每一格是否都和第一个相同。
			{
				return false;
			}
		}
	}
	return true;
}

void flip(int row, int col)
{
	for(int i=0; i<5; ++i)//map的范围是[6][6]即[0-5][0-5],操作用到的是[1-4][1-4],不会越界
	{
		int r = row + dr[i];
		int c = col + dc[i];
		map[r][c] = !map[r][c];
	}
}

void dfs(int row, int col, int dep)
{
	if(dep == step)
	{
		findaaa = isgoal();
		return;
	}
	if(findaaa || row == 5) return;

	flip(row, col);//给当前点执行flip
	if(col < 4) dfs(row, col + 1, dep + 1);
	else dfs(row + 1, 1, dep + 1);//如果列数超过4就换下一行,就是逐行深搜。

	flip(row, col);//如果没找到,把当前点翻回去,继续找下一个(此时dep就不 + 1了)。
	if(col < 4) dfs(row, col + 1, dep);
	else dfs(row + 1, 1, dep);
}

int main() {
	char c;
	for(int i = 1; i<=4; ++i)
	{
		for (int j = 1; j<=4; ++j)
		{
			cin >> c;
			if(c == 'b') map[i][j] = true;
		}
	}
	for(step = 0; step <= 16; ++step)//最多执行16步,一定能出结果
	{
		dfs(1, 1, 0);//从点(1,1)开始搜,初始化dep为0。
		if(findaaa) break;
	}
	if(findaaa)  cout << step << endl;
	else cout << "Impossible" << endl;
	return 0;
}

这是我看到的比较快捷的代码,用了位操作,我写了注释,转自:http://www.cppblog.com/Yusi-Xiao/archive/2009/03/21/77383.html

1753Accepted936K47MSG++1868B

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;

const int MAX_STATE = 65536;
const int ALL_WHITE_STATE = 0;
const int ALL_BLACK_STATE = 65535;
const int WIDTH_OF_BOARD = 4;
const int SIZE_OF_BOARD = WIDTH_OF_BOARD * WIDTH_OF_BOARD;

int convertPieceColorToInt(char color)//把颜色转换成0、1整型
{
	switch(color)
	{
	case 'b': return 1;
	case 'w': return 0;
	}
}

int flipPiece(int state_id, int position)
{
	state_id ^= (1 << position);//异或操作^,相应位置的1换成0,0换成1.

	if(position -4 >= 0) state_id ^= (1 << (position - 4));//上边的格翻过去
	if(position + 4 < SIZE_OF_BOARD) state_id ^= (1 << (position + 4));//下
	if(position % 4 != 0) state_id ^= (1 << (position - 1));//左
	if(position % 4 != 3) state_id ^= (1 << (position + 1));//右

	return state_id;
}

int main() {
	int current_state_id = 0;
	int state[MAX_STATE];
	queue<int> search_queue;

	memset(state, -1, sizeof(state));

	char color;

	for (int i = 0; i<SIZE_OF_BOARD; ++i)
	{
		cin >> color;
		current_state_id += convertPieceColorToInt(color) << i;//初始值,每一格的状态写到相应位置。
	}

	if(current_state_id == ALL_BLACK_STATE || current_state_id == ALL_WHITE_STATE)
	{
		cout << "0" << endl;
		return 0;
	}

	state[current_state_id] = 0;//用来存需要的步数。
	search_queue.push(current_state_id);

	int next_state_id;

	while(!search_queue.empty())//用队列实现深搜,每次把相邻的点加入队列。
	{
		current_state_id = search_queue.front();
		search_queue.pop();

		for(int i = 0; i<SIZE_OF_BOARD; ++i)
		{
			next_state_id = flipPiece(current_state_id, i);//再翻一个点i,结果为next_state_id。
			if(next_state_id == ALL_WHITE_STATE || next_state_id == ALL_BLACK_STATE)
			{
				cout << state[current_state_id] + 1 << endl;
				return 0;
			}
			if(state[next_state_id] == -1)//如果没有出现过,就入队,值为当前点的值 + 1
			{
				state[next_state_id] = state[current_state_id] + 1;
				search_queue.push(next_state_id);
			}
		}
	}

	cout << "Impossible" << endl;
	return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值