給定長寬的黑白棋棋盤擺滿棋子,每次操做能夠反轉一個位置和其上下左右共五個位置的棋子的顏色,求要使用最少翻轉次數將全部棋子反轉爲黑色所需翻轉的是哪些棋子。ios
這題剛開始被放到搜索的分類下了..然而這和搜索有什麼關係..沒經驗因此想了各類和搜索沾邊的方法,結果沒想出解法,直到看了網上的題解,壓根不是搜索。
具體解法:首先根據題目,每次操做都會影響到周圍的「棋子」,而要使得每一個1都被反轉爲0,那麼咱們就應當每次都反轉1下方的棋子以改變1爲0.
那麼,當咱們處理過1到n-1行的時候,前n-1行就都已是0了,最後咱們只須要檢查最後一行是否是所有爲0就能夠檢查此次的出操做是否正確了。若是正確且最小,那就存起來。最後輸出,萬事大吉。
固然,由於咱們要改變第x行的1爲0須要反轉的是x+1行的位置。而這個整個規則是咱們驗證一組操做是否能達到目的所用的,那麼咱們須要在驗證前先肯定操做(沒操做怎麼驗證..)。
因而根據規則內容可知,只須要能確認第一行的翻轉狀況,就可以推出下面全部的翻轉狀況並驗證是否正確。因而須要作的就是枚舉第一行的狀況了。算法
整個代碼分了四部分,處理輸入部分沒啥可說的,接下來就是doWork幹活部分了..
須要乾的活就是枚舉第一行的全部狀況而後對於每次枚舉都計算驗證是否符合要求以及反轉所需的次數。其中,第一行的狀態數量可使用左移運算優化(效率比pow高),因而總共枚舉的數量就有1<<col次。另外,由於這使得一行的狀態是由一個數字保存的,因此依然使用位運算取得是否翻轉的狀態。
將枚舉好的一次首行狀態存好後就能夠交給calc計算和驗證了。驗證就是經過上述翻轉規則操做。其中get(x,y)爲取得某個位置是否爲1的狀態的方法(過程)。
最後檢查結果就好。下面是代碼。
優化
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <queue> #define each(i,n) (int i=1;i<=(n);++i) #define INF 0x3f3f3f3f using namespace std; int row,col; int arr[20][20]; int flip[20][20],ans[20][20]; int dir[5][2] = { 0,0, 0,1, 0,-1, -1,0, 1,0 }; int get(int x,int y) { int c = arr[x+1][y+1]; for(int i = 0;i<5;i++) { int dx = x + dir[i][0]; int dy = y + dir[i][1]; if(dx >=0 && dx<row && dy>=0 && dy<col) { c+=flip[dx][dy]; } } return c&1; // with flip state, if odd return 1 } int calc() { for each(i,row-1) { for(int j = 0;j<col;j++) { if(get(i-1,j)) ++flip[i][j]; } } for(int i=0;i<col;i++) { // check last line if(get(row-1,i)) return 0; } int cnt = 0; for (int i=0;i<row;i++) { //統計翻轉的次數 for (int j=0;j<col;j++) { cnt += flip[i][j]; } } return cnt; } void doWork() { int cnt = INF; for(int i=0;i<(1<<col);i++) { //from 0000 to 1111 memset(flip,0,sizeof(flip)); for(int j=0;j<col;j++) { flip[0][col-j-1] = (i>>j)&1; //get pos state form binary number } int num = calc(); if (num<cnt && num!=0) { cnt = num; memcpy(ans,flip,sizeof(flip)); } } if (cnt==INF) printf("IMPOSSIBLE\n"); else { for (int i=0;i<row;i++) { printf("%d",ans[i][0]); for each(j,col-1) { printf(" %d",ans[i][j]); } printf("\n"); } } } int main() { while(~scanf("%d%d",&row,&col)) { memset(arr,0,sizeof(arr)); for each(i,row) { for each(j,col) { scanf("%d",&arr[i][j]); } } doWork(); } }