POJ 1753

题目大意:

有 4x4 的正方形,每个格子要么是黑色,要么是白色,当把一个格子的颜色改变(黑->白或者白->黑)时,其周围上下左右(如果存在的话)的格子的颜色也被反转,问至少反转几个格子可以使 4x4 的正方形变为纯白或者纯黑?

//1753
//动态规划
//Flip Game

#include<iostream>
#include<string>
#include<bitset>

#define MAX 100000

using namespace std;

typedef unsigned short grid;

//翻转格子
//flipPos : 翻转格子的位置;  item: 被翻转的对象
//返回翻转后的grid
grid Flip( int flipPos, grid item )
{
	item ^= (1 << (flipPos-1) );
	if(flipPos > 4){
		item ^= (1 << (flipPos-4-1) );
	}
	if(flipPos % 4 != 1){
		item ^= (1 << (flipPos-1-1) );
	}
	if(flipPos % 4 != 0){
		item ^= (1 << (flipPos+1-1) );
	}
	if(flipPos < 13){
		item ^= (1 << (flipPos+4-1) );
	}

	return item;
}



int main(int argc, char *argv[])
{
	string str;
	string lineStr;
	grid gridOne = 0;
	int i;

	//input
	i = 0;
	while( i++ < 4 ){
		cin >> lineStr;
		str += lineStr;
	}

	//change string to unsigned shor
	//b->1, w->0
	i = 15;
	for( string::iterator c = str.begin();  c != str.end();  c++ ){
		if( *c == 'b' ){
			gridOne |= (1 << i);
		}
		i--;
	}

	if( gridOne == 0 ||  gridOne == 0xffff ){
		cout << 0 << endl;
		return 0;
	}
	

	//calculate time
	typedef struct Table{
		grid gridItem;
		int step;	//第几次翻转
		int pos;
	}Table;

	Table table[MAX];
	bool flags[MAX] = {false};	//对已经出现过的情况做标记;没有这个可能会出现死循环

	table[0].gridItem = gridOne;
	table[0].pos = -1;
	table[0].step = 0;
	flags[gridOne] = true;	

	grid item;
	int current = 0;	//当前k情况
	int capacity = 1;	//所有可能情况的总数

	//test
	//cout << str << endl;
	//cout << bitset<sizeof(grid)*8>(gridOne) << endl;
	//cout << "test end";
	

	while( current != capacity ){
		item = table[current].gridItem;

		//位置从1开始
		for(i=1; i<17; i++){
			if( table[current].pos != i ){
				grid newItem = Flip(i, item);

				if( flags[newItem] == false ){
					table[capacity].gridItem = newItem;
					table[capacity].pos = i;
					table[capacity].step = table[current].step + 1;
					flags[newItem] = true;

					if( table[capacity].gridItem == 0 || table[capacity].gridItem == 0xffff ){
						cout << table[capacity].step << endl;
						return 0;
					}

					capacity++;
				}
			}
		}
		current++;
	}	

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

下面说说自己的收获

  • 创建结构数组比结构体里包含数组要方便
  • 这里使用线性存储树结构
  • 在使用动态规划时,不仅仅要注意“存储表”的创建,同时更重要的是去除重复情况,这题使用flags标记来过滤重复的grid。这题不过滤重复情况可能会陷入死循环。
  • 这题通过结构体来记录翻转次数step,这种方法虽然空间消耗大,但是写法简单。如果只用一个变量记录翻转次数step,写法复杂,考虑的逻辑情况较多。
原文地址:https://www.cnblogs.com/friedCoder/p/12245105.html