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,写法复杂,考虑的逻辑情况较多。