思路: 位运算加Bfs ,参考了别人的思路,但是觉得只枚举第一行就可以,不用全部都枚举,今天太晚了,明天想一想
code
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <limits>
#include <vector>
#include <bitset>
#include <string>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <string.h>
#include <iostream>
#include <algorithm>
#define Si set<int>
#define LL long long
#define pb push_back
#define PS printf(" ")
#define Vi vector<int>
#define LN printf("\n")
#define lson l,m,rt << 1
#define rson m+1,r,rt<<1|1
#define SD(a) scanf("%d",&a)
#define PD(a) printf("%d\n",a)
#define SET(a,b) memset(a,b,sizeof(a))
#define FF(i,a) for(int i(0);i<(a);i++)
#define FD(i,a) for(int i(a);i>=(1);i--)
#define FOR(i,a,b) for(int i(a);i<=(b);i++)
#define FOD(i,a,b) for(int i(a);i>=(b);i--)
#define readf freopen("input.txt","r",stdin)
#define writef freopen("output.txt","w",stdout)
const int maxn = 65536;
const int INF = ~0U>>1;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const double pi = acos(-1.0);
using namespace std;
int ans;
bool visited[maxn]; //default false;
struct state{
int s,step;
}q[maxn];
int Filp(int sta,int pos){
sta ^=(1<<pos); //当然先把自己给翻了
if(pos>3) sta^=(1<<(pos-4)); //翻转上面的
if(pos<12) sta^=(1<<(pos+4));
if(pos%4>0) sta^=(1<<(pos-1));
if(pos%4<3) sta^=(1<<(pos+1));
return sta;
}
bool bfs(int sta){
int front,rear;
front=rear=0;
q[rear].s=sta;
q[rear++].step=0;
while(front<rear){
state tmp=q[front++];
if(tmp.s == 0 || tmp.s==65535){
ans=tmp.step;
return true;
}
FF(i,16){
int k=Filp(tmp.s,i);
if(!visited[k]){
visited[k]=true;
q[rear].s=k;
q[rear++].step=tmp.step+1;
}
}
}
return false;
}
int main()
{
int sta=0;
char ch;
FF(i,16){
scanf(" %c",&ch);
if( ch == 'b' ){
sta+=(1<<i);
}
}
if( sta==0 || sta==65535) puts("0");
else{
if( bfs(sta))
PD(ans);
else
puts("Impossible");
}
return 0;
}
第二种想法新鲜出炉了!!!!但是,好像耗时比第一种方法更多了,不过却压制了枚举范围,估计矩阵可达20*20;
code里面有详细的注释
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <limits>
#include <vector>
#include <bitset>
#include <string>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <string.h>
#include <iostream>
#include <algorithm>
#define Si set<int>
#define LL long long
#define pb push_back
#define PS printf(" ")
#define Vi vector<int>
#define LN printf("\n")
#define lson l,m,rt << 1
#define rson m+1,r,rt<<1|1
#define SD(a) scanf("%d",&a)
#define PD(a) printf("%d\n",a)
#define SET(a,b) memset(a,b,sizeof(a))
#define FF(i,a) for(int i(0);i<(a);i++)
#define FD(i,a) for(int i(a);i>=(1);i--)
#define FOR(i,a,b) for(int i(a);i<=(b);i++)
#define FOD(i,a,b) for(int i(a);i>=(b);i--)
#define readf freopen("input.txt","r",stdin)
#define writef freopen("output.txt","w",stdout)
const int maxn = 65536;
const int INF = ~0U>>1;
const int dx[]={0,0,1,0,-1};
const int dy[]={0,1,0,-1,0};
const double pi = acos(-1.0);
using namespace std;
//为了增加通用性,决定加入x,y来标识坐标;
int N,M,ans; //N rows,M cols;
int Flip(int x,int y,int state){ //把自己翻转了
if(x >=0 && x< N && y>=0 && y<M)
state ^=1<<(x*N+y);
return state;
}
void dfs(int cur,int num,int st,int flag){
if(cur==M){
if(st == 0xffff || st == 0)
ans=ans>num?num:ans;
return;
}
FF(j,M){
//这里是将上一行的状态提取出来,因为上一行的选择决定了下一行的操作
//如果上一行的跟目标状态不一样,那么就要翻转这个
if( ( (st & (1<<((cur-1)*N+j)))>>((cur-1)*N+j) ) ^ flag ){
int x,y;
FF(k,5){
x=cur+dx[k];
y=j+dy[k];
st=Flip(x,y,st);
}
++num;
}
}
dfs(cur+1,num,st,flag);
}
int main()
{
N=M=4;
char ch;
int sta=0;
ans=INF;
FF(i,N) FF(j,M){
scanf(" %c",&ch);
sta<<=1;
if(ch=='b')
sta+=1;
}
FF(i,16){
int num = 0, st = sta;
FF(j,M)
{
if(i & (1 << j)) //这句话很有内涵
/*
0000&0001==0000; 0000&0010==0000;0000&0100==0000;0000&1000==0000;不行
0001&0001==0001@;........依次下去 ,把最右下的颜色翻转
0010&0010;
0011&0001; 0011& 0010; 0011& 0011;
0100&
0101&
0110&
0111& 看客们应该看出来了吧!
1000& 用循环枚举了16种翻牌情况的全排列!!
1001&
1010& 仰慕想出此办法的神牛!!
1011&
1100&
1101&
1110&
1111&
*/
{
for(int k = 0; k < 5; k ++)
{
int x = 0 + dx[k];
int y = j + dy[k];
st=Flip(x, y, st);
}
num ++;
}
}
dfs(1, num, st, 0);
dfs(1, num, st, 1);
}
if(ans!=INF) PD(ans);
else puts("Impossible");
return 0;
}