从今天开始,真的要一步一脚印,从最简单的做起,争取最短时间进步!!!
题意大概是给你一个4×4棋盘,棋盘上不是‘b'就是'w',要你用最少的翻转步数是它们全部变成'w'或全部变成'b';每次翻转时,该位置的上,下左,右也会随着翻转。
看了别人家的题解才想出来的。。。
大概思路是位运算加bfs;首先4×4不大,所以考虑把棋盘上的字母转换成一个二进制数字,每一个数字对应着一个棋盘的状态,如果全部是1,即全部是’b'此时的数字是65535,反过来全部是‘w',数字是0;所以在输入棋盘时,首先把棋盘的状态转换成一个数字表示,其实就是求这个数字经过最少的变化次数到达65535或0;
对于棋盘每一个状态,都去枚举它可能翻转的棋子,由于对于每一颗棋子,只有翻与不翻之分,偶数次其实就是不翻,为了达到最少的步数就必须避免重复前面的状态,这里还用了一个数组进行标记。对于从第一颗到第16颗棋子,翻的时候对周围都会造成影响,先假设前一个状态为: wwww wwww wwww wwww 即二进制表示为0000 0000 0000 0000,十进制对应为0。若此时选定左上角第一个棋子进行操作,根据规则,它右边和下边的也要同时进行变换(因为其左边和上边为空,不做考虑),之后,相应的状态用二进制表示,应变为:1100 1000 0000 0000,十进制值为51200。这个过程相当于对十进制数51200进行对十进制数0的异或操作,即next=0^(51200),而51200这个数则可以根据对十进制数1进行相应的左移操作得到。同时,我们知道,棋牌总共有16个位置,也就是说相应的不同的操作也有16种,即有16个不同的数经过异或操作用来改变前一个状态的值。那么,就先将这16个数枚出来吧,代码如下:
int dir[4][2]={0,1,-1,0,0,-1,1,0};
void init()
{
memset(change,0,sizeof(change));
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
change[4*i+j]^=(1<<((3-i)*4+3-j));
for(int k=0;k<4;k++)
{
int a=i+dir[k][0];
int b=j+dir[k][1];
if(a<0||a>3||b<0||b>3)continue;
change[4*i+j]^=(1<<((3-a)*4+3-b));
}
}
for(int i=0;i<16;i++)
{
cout<<change[i]<<' ';
cout<<endl;
}
}
主代码:
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <cstdio>
#include <cstdlib>
using namespace std;
char a[4][4];
int change[16]={51200,58368,29184,12544,
35968,20032,10016,4880,
2248,1252,626,305,
140,78,39,19
};
bool visit[65537];
//位运算加bfs
struct node
{
int state;
int step;
};
int solve(int s)
{
memset(visit,false,sizeof(visit));
queue<node>q;
node cur,tmp;
cur.state=s;
cur.step=0;
q.push(cur);
visit[s]=true;
//if(cur.state==0||cur.state==65535)return cur.step;
while(!q.empty())
{
cur=q.front();
q.pop();
if(cur.state==0||cur.state==0xffff)return cur.step;
for(int i=0;i<16;i++)
{
tmp.state=cur.state^change[i];
tmp.step=cur.step+1;
if(visit[tmp.state])continue;
if(tmp.state==0||tmp.state==0xffff)return tmp.step;
q.push(tmp);
visit[tmp.state]=true;
}
}
return -1;
}
int main()
{
while(scanf("%s",a[0])!=EOF)
{
for(int i=1;i<4;i++)scanf("%s",a[i]);
int st=0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
if(a[i][j]=='b')
st^=(1<<((3-i)*4+3-j));
}
//cout<<state<<endl;
int sum=solve(st);
if(-1==sum)cout<<"Impossible"<<endl;
else cout<<sum<<endl;
}
return 0;
}