1)总的状态数是一定的,共0~~65535=65536种状态;
2)首先理解一点,先点(0,0)再点(0,1)与先点(0,1)再点(0,0)对结果不造成任何影响.因此遍历棋盘的16个位置,将每次点击后的状态id利用树状结构保存.如:
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include <string>
#include <math.h>
#define N 1000000
using namespace std;
//BFS+枚举有限的状态数:2^16=65536种
int que[N];
int flag[65536];
int step[65536];
int front=0,rear=0;
//翻转某位,只需将该位与1抑或
int flip(int state,int pos) //翻转pos及其周围位置
{
state^=(1<<pos);
if((pos-4)>=0) state^=(1<<(pos-4)); //翻转上方
if((pos+4)<=15) state^=(1<<(pos+4)); //翻转下方
if(pos%4!=0) state^=(1<<(pos-1)); //翻转左方
if(pos%4!=3) state^=(1<<(pos+1)); //翻转右方
return state;
}
//广搜
int bfs()
{
int tag=0,state,temp;
while(front<rear){ //当队列不为空
state=que[front++];
for(int i=0;i<16;i++){ //枚举当前状态下,翻转16个棋子后的状态
temp=flip(state,i);
if(temp==0||temp==65535){ //全0或全1
tag=1;
flag[temp]=1;
step[temp]=step[state]+1;
break;
}
else if(!flag[temp]){
que[rear++]=temp;
flag[temp]=1;
step[temp]=step[state]+1;
}
}
if(tag) break;
}
return tag;
}
int main()
{
int i,j;
int state=0;
char s[5];
for(i=0;i<4;i++){
scanf("%s",s);
for(j=0;j<4;j++){
if(s[j]=='b') //令'b'=1,'w'=0,当该位为0时,不需加
state|=(1<<(i*4+j)); //该位为1时,state+=1^位置
}
}
if(state==0||state==65535) printf("0\n");
else{
que[rear++]=state;
flag[state]=1;
memset(step,0,sizeof(step));
if(bfs()) printf("%d\n",flag[0]==1?step[0]:step[65535]);
else printf("Impossible\n");
}
return 0;
}
这道题是搜了题解之后才写出来的,刚开始总是不知道该如何枚举,忽略了状态数是有限的这一条件。
做完这道,再去做poj2965 http://poj.org/problem?id=2965 ,就简单多了。唯一不同的就是多了保存搜索路径;我能想到的就是保存当前状态的前一个状态,以及前一个状态到达当前状态的路径值;总体感觉空间效率有点儿低。。。附上代码:
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <iostream>
#include <map>
#include <vector>
#include <queue>
#include <set>
#include <string>
#include <math.h>
#define N 1000000
using namespace std;
char s[5];
int que[N];
int flag[65536];
int step[65536];
struct stpath{
int prest;
int ps;
}pp[65536]; //保存路径
struct path{
int x;
int y;
}r[65536];
int initial() //初始化
{
int state=0;
for(int i=0;i<4;i++){
scanf("%s",s);
for(int j=0;j<4;j++){
if(s[j]=='+')
state|=1<<(i*4+j); //求初始状态
}
}
return state;
}
int switching(int temp,int pos) //状态翻转
{
temp^=(1<<pos);
int x=pos/4;
int y=pos%4;
for(int j=0;j<4;j++){ //翻转row x
int pr=x*4+j;
if(pr!=pos) temp^=(1<<pr);
}
for(int i=0;i<4;i++){ //翻转col Y
int pc=i*4+y;
if(pc!=pos) temp^=(1<<pc);
}
return temp;
}
int bfs(int state){ //广度优先搜索
int front=0,rear=0;
que[rear++]=state;
flag[state]=1;
while(front<rear){
int pstate=que[front++];
for(int i=0;i<16;i++){
int temp=switching(pstate,i);
if(temp==0){
pp[temp].prest=pstate; //保存前一个状态
pp[temp].ps=i; //保存状态翻转路径
step[temp]=step[pstate]+1;
flag[temp]=1;
return step[0];
}
else if(!flag[temp]){
pp[temp].prest=pstate; //保存前一个状态
pp[temp].ps=i; //保存状态翻转路径
que[rear++]=temp;
step[temp]=step[pstate]+1;
flag[temp]=1;
}
}
}
}
void savePath(){ //保存路径
int k=0;
int temp=0;
while(pp[temp].prest!=-1){
r[k].x=pp[temp].ps/4+1;
r[k++].y=pp[temp].ps%4+1;
temp=pp[temp].prest;
}
return;
}
int main()
{
int k,state,temp;
state=initial();
memset(step,0,sizeof(step));
pp[state].prest=-1;
k=bfs(state);
savePath();
printf("%d\n",k);
for(int i=k-1;i>=0;i--){
printf("%d %d\n",r[i].x,r[i].y);
}
//system("pause");
return 0;
}