POJ1753 狀態壓縮( BFS) 棋盤問題

2021-07-14 20:16:29 字數 3184 閱讀 2244

棋盤問題,改變乙個子的顏色,這個子以及這個子周圍的四個位置(左右上下)的子分別變色,求最少的改變次數。

此類題大部分應該可以用狀態壓縮+暴力搜尋解決。純粹找規律不太合理。

1)第一種方法,狀態壓縮後bfs暴力搜尋。因為棋盤很小,只有16個格仔,列舉所有的狀態共有2^16=65536種。所以有可以用int陣列儲存65535個狀態用以確認哪乙個出現了哪乙個沒出現,然後暴力列舉+bfs的搜尋方式。

2)第二種,或者不進行狀態壓縮,直接按順序,確定改變次數為1、改變次數為2...改變次數為16,在每乙個確定的改變次數下用dfs求解。(直接dfs是從1到16一條路走到頭然後不斷回溯,第一次得到的顏色統一的改變次數未必是最小次數,所以改用有些bfs思想的dfs,但因為沒有像bfs那樣儲存狀態,所以做了一些重複的工作,時間會比第一種方法慢。)

3)wa,還未除錯出來:

因為意識到解題的關鍵是,每一位置的子改變一次和改變兩次其實是一樣的&&改變第a個子然後改變第b個子的效果等同於先改變第b個子然後改變第a個子即與順序無關,所以我設想不用狀態壓縮,直接按順序只改變當前子之後的子不斷bfs列舉,自然而然就可以避免重複的搜尋工作。具體是指,第一輪,依次改變棋盤上第乙個、第二個、第十六個子,共十六種情況存入佇列,然後第二輪,從佇列中取出改變第乙個子後的狀態,依次嘗試改變第乙個子往後的子,改變之後存入佇列...第x輪,從佇列中取出隊首即上一輪中改變第m個子後的狀態,那麼我們只需考慮接下來改變第m個子之後的子即可,而不用考慮改變第m個子之前的子,因為那種情況相當於先改變第m個子之前的子此時改變第m個子。

我覺得我的思想應該沒問題,起到的效果是等同於狀態壓縮中記錄狀態的作用的...不過就是沒ac,樣例過,疑問!?

1)ac**:

#include #include #include using namespace std;

//int mmap[5][5]=;

int dir[5][2]=,,,,};

int visted[65536]=;

int state[16];

int ini_state;

int flag;

int step;

struct boards;

queueq;

void initialize()

temp^=(1<<( (x-1)*4+y -1 ));

}state[(i-1)*4+j-1]=temp;}}

}void bfs()

struct boards next_board;

for(int i=0;i<16;i++)}}

return ;

}int main()

}//cout<

2)ac**:

#include #include using namespace std;

int mmap[5][5];

int dir[5][2]=,,,,};//左 上 右 下 中

//int dir[5][5]=,,,,};

int sum;

int flag=0;

int judge()}}

return 1;

}void flip(int x,int y)

}}void dfs(int x,int y,int obj,int cur_step)

if(flag||x==5)

flip(x,y);

/* if(y<4)

else

*/ if(y+1<=4&&x<=4)

dfs(x,y+1,obj,cur_step+1);

else if(y==4)

flip(x,y);//一定注意!不用bfs,而是dfs,每次改變的東西當return回來之後一定要狀態還原!

/* if(y<4)

else

*/ if(y+1<=4&&x<=4)

dfs(x,y+1,obj,cur_step);

else if(y==4)

return ;

}int main()}}

int step=0;//當前翻轉棋子個數

for(int l=0;l<=16;l++);

int dir[4][4]=,,,};//左上右下

queue q;

int judge(struct boards boards_judge)}}

return 1;

}int reserve()

else

}if(judge(boards_future))

q.push(boards_future);

//boards_cur.sum--;//!假如沒有boards_future,直接q.push(boards_cur),然後再對boards_cur操作,是否,放入佇列的就不再受影響----是的!不受影響}}

return 0;

}int main()

}board.sum=0;

sum=0;

board.x_past=-1;

board.y_past=-1;

q.push(board);

if(judge(board))

else

if(state==-1)}}

if(sum!=-1)

cout<

wa**第二份

#include #include using namespace std;

int mmap[4][4];

int dir[5][2]=,,,,};//左 上 右 下 中

int sum;

int flag=0;

int judge()}}

return 1;

}void flip(int x,int y)

}}void dfs(int x,int y,int obj,int cur_step)

else

}for(int i=x;i<4;i++)

if(i<0||i>3||j<0||j>3)

flip(i,j);

dfs(i,j,obj,cur_step+1);

flip(i,j);}}

return ;

}int main()}}

int step=0;//當前翻轉棋子個數

for(int l=0;l<=16;l++){//應該翻轉的棋子個數

dfs(0,-1,l,step);

if(flag==1){

cout<

POJ 1753 BFS 狀態壓縮

非常普通的一道bfs題,做的時候貪快,沒想好就寫了。唉。對於給的一盤棋,最多只有 2 16 種翻法,並且翻的先後順序不影響結果,所以只需要bfs列舉一下就好了 對於每出現過的一種狀態,用狀態壓縮的數值標記一下,不用再進入佇列 否則會超時或者死迴圈啦 暴力 模擬一下 每次檢查是否 全黑65535 或者...

poj 1753 位壓縮 搜尋

題意 有乙個4 4的方格,每個方格中放一粒棋子,這個棋子一面是白色,一面是黑色。遊戲規則為每次任選16顆中的一顆,把選中的這顆以及它四周的棋子一併反過來,當所有的棋子都是同乙個顏色朝上時,遊戲就完成了。現在給定乙個初始狀態,要求輸出能夠完成遊戲所需翻轉的最小次數,如果初始狀態已經達到要求輸出0。如果...

廣度搜尋 POJ 1753

題意 乙個4 4的棋盤,每個格仔放著乙個棋子。棋子一面是白色,一面是黑色。一次操作可以將某乙個格仔以及上下左右共5個格仔的棋子都翻過來,即白色變黑色,黑色變白色。現在給出一種棋盤狀態,問最少需要幾次操作可以將棋盤全部變為同種顏色。輸入 sample input bwwb bbwb bwwb bwww...