题目链接:http://poj.org/problemstatus?problem_id=2965&start=120&orderby=time&language=-1
这个题目也比较简单,首先要明确一点,就是每一点翻转的顺序是没有要求的,也就是一点要么翻转,要么就不翻转,和顺序无关,明白了这一点这个
题目就简单了,一共就2^16种情况,用二进制位枚举一下就OK 了,二进制1表示翻转0表示不翻转;
其次就是一些技巧上的优化
第一:求数字二进制为1的个数,这个用x&x-1这个有多少一就多少次,应该是最快的速度了
第二:把开始char类型的转换成bool型的,方便处理
第三:用位运算计算那一位是否为1,这样速度快点
第四:用G++交,可能GNU的编译器对位运算的优化要好一些
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
#define maxn 1<<16
char rec[4][4];
bool map[4][4];
bool temp[4][4];
int init()
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
if(rec[i][j]=='+')
map[i][j]=true;
else
map[i][j]=false;
return 0;
}
bool is_ok()
{
bool flag=false;
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
{
flag=temp[i][j]||flag;
}
return flag==false;
}
int num_of_two(int a)
{
int num=0;
while(a)
{
a=a&(a-1);
num++;
}
return num;
}
int change(int i,int j)
{
int a;
for(a=0;a<4;a++)
temp[i][a]=!temp[i][a],temp[a][j]=!temp[a][j];
temp[i][j]=!temp[i][j];//three
return 0;
}
bool find_ans(int k)
{
int i;
for(i=0;i<16;i++)
{
if(k&(1<<i))
change(i%4,i/4);
}
return is_ok();
}
int out_put(int k)
{
for(int i=0;i<16;i++)
{
if(k&(1<<i))
printf("%d %d\n",i%4+1,i/4+1);
}
return 0;
}
int main()
{
int i,j,k;
int ans=0,num_two,n;
while(scanf("%s",rec[0])!=EOF)
{
num_two=10000;
ans=0;
scanf("%s%s%s",rec[1],rec[2],rec[3]);
init();
for(i=0;i<maxn;i++)
{
n=num_of_two(i);
if(n>=num_two)
continue;
memcpy(temp,map,sizeof(map));
if(find_ans(i))
ans=i,num_two=n;
}
printf("%d\n",num_two);
out_put(ans);
}
return 0;
}