这个题用bfs搜索过不了了。于是上网学习了某位大神用位运算枚举的办法。。
摘自discuss:
首先应该明白两点: 1 不论翻转执行的先后序列如何,结果都一样。 2 每一个点(i,j)最多做一次翻转。(由1不难得到)
交C++反而比G++要快。。不可思议。。
用0到2^16表示所有可能的翻转的位置,然后依次翻转看看是否得到全0即开的状态,如果可以则记录下最小值和这种该翻转情况。最后输出所有要翻转的位置。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
int p[20];
void flip(int x,int y,int &s)
{
for(int i=0; i<4; ++i)
{
s^=p[x*4+i];
s^=p[i*4+y];
}
s^=p[x*4+y];
}
int main()
{
for(int i=0; i<=16; ++i)
p[i]=pow(2.0,i);
int init=0,s;
char str[10];
for(int i=0; i<4; ++i)
{
gets(str);
for(int j=0; j<4; ++j)
if(str[j]=='+')
init+=p[i*4+j];
}
int mystep,mn=100;
for(int i=0; i<=p[16]; ++i)
{
s=init;
int step=0;
for(int j=0; j<=16; ++j)
if(i&p[j])
{
step++;
flip(j/4,j%4,s);
if(s==0&&step<mn)
{
mn=step;
mystep=i;
}
}
}
printf("%d\n",mn);
for(int i=0; i<=16; ++i)
if(mystep&p[i])
printf("%d %d\n",i/4+1,i%4+1);
return 0;
}