这道题就是所谓的“关灯问题”。在《算法设计与分析基础》课后习题中见过。 乍一看,最容易想到用16个(0、1)变量列一个线性方程组(16维的),然后高斯消去求解。但是感觉高斯消去法写起来太累人。又想别的方法。出现在脑袋里的是暴力法,由于只有2^16个解,所以暴力是可以解决的。然后又想到用一个int型数据的低16位表示棋盘,然后对棋盘进行位运算操作效率较高。
discuss里有很多所谓的官方测试数据,可以先测试一下再提交。
poj1753代码:
#include<iostream>
#include<fstream>
#include<time.h>
using namespace std;
inline void set0(int &data,int index)
{
data&=(~(1<<index));
}
inline void set1(int &data,int index)
{
data|=(1<<index);
}
inline int getbit(const int &data,int index)
{
return data&(1<<index);
}
int data;
void put(char *ch,int index)
{
for(int i=0;i<4;i++,index++)
{
if(ch[i]=='b')
{
set0(data,index);
}
else if(ch[i]=='w')
{
set1(data,index);
}
}
}
int rem[16]={};
//0表示b 1表示w
void solve()
{
const int final0=0;
const int final1=65535;
int change;
int temp=data;
int min=100;
for(change=0;change<65536;change++)
{
//data 根据i的每一位做相应变化
for(int i=0;i<16;i++)
{
if(getbit(change,i)!=0)
{
data=data^rem[i];
}
}
if(data==final0||data==final1)
{
int count=0;//统计i中 “1” 的个数,
for(int i=0;i<16;i++)
{
if(getbit(change,i)!=0)
count++;
}
if(count<min)
min=count;
}
data=temp;
}
if(min==100)
cout<<"Impossible"<<endl;
else
{
cout<<min<<endl;
}
}
int main( )
{
memset(rem,0,sizeof(int)*16);
for(int i=0;i<16;i++)
{
set1(rem[i],i);
if(i-4>=0)
set1(rem[i],i-4);
if(i%4!=0)
set1(rem[i],i-1);
if(i%4!=3)
set1(rem[i],i+1);
if(i+4<16)
set1(rem[i],i+4);
}
ifstream cin("input.txt");
char ch[5];
while(cin>>ch)
{
int index=0;
data=0;
put(ch,index);
index+=4;
for(int k=0;k<3;k++)
{
cin>>ch;
put(ch,index);
index+=4;
}
solve();
}
return 0;
}