Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 29921 | Accepted: 12975 |
Description
Input
Output
Sample Input
bwwb bbwb bwwb bwww
Sample Output
4
Source
题意为有一个4*4的棋盘,由黑棋子和白棋子填满着(黑棋子用'b'表示,白棋子用'w'表示),我们所做的就是翻转棋子,黑色棋子经过一次翻转成为白色棋子,白色棋子经过一次翻转成为黑色棋子,翻转的规则为:每次随机选择一枚棋子,翻转它以及它周围的棋子(上下左右),问最少经过翻转几次,棋盘所呈现的状态为全黑或者全白。
我们用一个16位的二进制数来表示棋盘的一个状态,比如 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1(16个1)即数字65535,我们假设1代表是黑棋子,那么65535这个状态表示为16个棋子全是黑色,符合题意要求,而0这个状态表示为棋子全是白色,也符合要求。 不同的数字代表着棋盘不同的状态 比如 1 1 1 1 1 1 0 1 1 1 00 1 1 0 0 代表着有5枚白棋子,11枚黑棋,且可以知道白棋所在的位置 ,即 在第二行的第三个 (二进制数从右到左第9位,位数从0开始数),第三行的第三第四个,第四行的第三第四个。 即棋盘的状态为
b b b b
b b w b
b b w w
b b w w 我们把棋盘上的棋子从上到下,从左向右编号,即0,1,2,3~ 15,那么它的编号和它在一个二进制表示的状态中的位数(第几位)之间的关系为 label= 15 - 编号。比如棋盘中第一行第二列的b编号为1,它的位置在 1 1 1 1 1 1 0 1 1 1 00 1 1 0 0 右数第14位(从0开始).
如何在一个16位的二进制数中翻转第i枚棋子,使其状态发生变化? 0^1 = 1 1^1=0 b=b^(1<<i) 表示 把二进制数b中的第i位取反(0变为1,1变为0) ,所以我们要使第i枚棋子翻转,首先根据 label= 15- 编号,求出这枚棋子是数b中的第几位,然后 b^(1<<label),就可以了。
求最短的翻转次数,用BFS广度优先搜索来做。一个step[]数组记录步数.队列中存的是棋盘的每一个状态(即一个16位的二进制数). 把棋盘的初始状态加入队列中,然后一开始16种选择(16个棋子),选择任何一个棋子都可以。当选择一个棋子使其翻转,也要把它周围的棋子翻转,这样就得到了一个新状态tmp , first为队首状态,step[tmp]=step[first]+1. 每次取队首,然后再不断扩充状态。判断当前棋盘状态,如果它等于0 或者 65535,说明棋盘已经呈全黑或全白状态,达到要求。 需要注意的是一个到达的新状态可能以前已经到达过,那样如果这样进行下去就进入了死循环,所以用vis[状态] 数组记录当前状态是否到达过,如果到达过就不能再加入队列中。
代码:
#include <iostream> #include <string.h> #include <queue> using namespace std; const int maxn=65535; bool vis[maxn+1]; int step[maxn+1]; bool ok=0; void bfs(int d) { if(d==0||d==maxn)//棋盘一开始状态 { cout<<0<<endl; ok=1; return; } memset(vis,0,sizeof(vis)); vis[d]=1; queue<int>q; int temp,first; temp=d; step[temp]=0; q.push(temp); while(!q.empty()) { first=q.front(); q.pop(); for(int i=0;i<16;i++) { temp=first; int label=15-i;//求第i枚棋子对应二进制数中的第几位 temp^=1<<(label); int tm; tm=label+4;//处理上边的棋子 if(tm!=19&&tm!=18&&tm!=17&&tm!=16) temp^=1<<tm; tm=label-4;//处理下边的棋子 if(tm!=-1&&tm!=-2&&tm!=-3&&tm!=-4) temp^=1<<tm; tm=label+1;//处理左边的棋子 if(tm!=16&&tm!=12&&tm!=8&&tm!=4) temp^=1<<tm; tm=label-1;//处理右边的棋子 if(tm!=11&&tm!=7&&tm!=3&&tm!=-1) temp^=1<<tm; if(temp==0||temp==maxn)//全白或全黑的状态 { cout<<step[first]+1<<endl; ok=1; return ; } if(!vis[temp])//已经到达过的状态不进队列 { vis[temp]=1; q.push(temp); step[temp]=step[first]+1; } } } } int main() { char color; int d=0; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { d<<=1;//在二进制数中的最后面加一个0,代表白色 cin>>color; if(color=='b') d+=1;//最后一位变为1,代表黑色 } bfs(d); if(!ok) cout<<"Impossible"<<endl; return 0; }