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;
}