棋盤問題,改變乙個子的顏色,這個子以及這個子周圍的四個位置(左右上下)的子分別變色,求最少的改變次數。
此類題大部分應該可以用狀態壓縮+暴力搜尋解決。純粹找規律不太合理。
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...