Fliptile POJ - 3279 開關反轉問題 + 位運算
阿新 • • 發佈:2018-11-19
解這題的關鍵思想
第一行的狀態決 定了後面所有行的狀態
奶牛踏瓷磚問題,顯然奶牛踏 1 次和奶牛踏3次,效果是一樣的,那麼每塊瓷磚的翻轉次數,只可能是 0次或一次。
那麼現在問題就轉換成了列舉結果矩陣中的每一個數值是 1 還是0 ,但是 M 和 N 的最大值為 15,單純暴力的話,2^15*15 一定會超時。
問題的關鍵在於前一行的狀態決定了後一行的狀態,所以一旦第一行確定,後面的所有行就確定了。現在就可以轉化成單純的列舉每一行或者每一列。 時間複雜度 2^15 ,很小。
起始狀態 踏瓷磚次數矩陣 1 0 0 1 0 0 0 0 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1 1 0 0 1 0 0 0 0
我實現的程式碼就是 列舉第一列的狀態 ,計算出踏瓷磚的狀態矩陣,判斷最後該情況是否可取,因為照這種前一列推後一列的狀態,最後一列的狀態不一定是全0,所以要判斷一下。
程式碼如下:
#include<iostream> #include<cstring> using namespace std; int statu[20]; int m,n; int maze[20][20]; int result[20][20]; //儲存最終結果 int mid[20][20]; //儲存列舉的結果 int mid_maze[20][20]; //儲存中間變化的迷宮 int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}}; int max_time; void flip(int x,int y) { mid_maze[x][y] = (mid_maze[x][y]+1)%2; for(int i=0;i<4;i++) { int px =x+dir[i][0]; int py = y+dir[i][1]; if(px<0||py<0||px>=m||py>=n) continue; mid_maze[px][py] = (mid_maze[px][py]+1)%2; } } int hasre; int main() { ios::sync_with_stdio(false); while(cin>>m>>n) { hasre=0; memset(mid_maze,0,sizeof(mid_maze)); memset(maze,0,sizeof(maze)); max_time = 0x3f3f3f3f; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { cin>>maze[i][j]; } } for(int pp=0; pp< 2<<n;pp++) { int counts = 0; int p =pp; memset(statu,0,sizeof(statu)); memset(mid,0,sizeof(mid)); while(p!=0) { statu[counts++] = p&1; p = p>>1; } for(int i=0;i<m;i++) for(int j=0;j<n;j++) mid_maze[i][j] = maze[i][j]; counts =0; for(int i=0;i<n;i++) { mid[0][i] = statu[i]; if(statu[i]) { flip(0,i); counts++; } } for(int i=1;i<m;i++) { for(int j=0;j<n;j++) { if(mid_maze[i-1][j] ==1) { mid[i][j]=1; flip(i,j); counts++; } } } int ops=1; for(int i=0;i<n;i++) { if(mid_maze[m-1][i]==1) { ops=0; break; } } if(ops==0)continue; if(counts < max_time) { max_time = counts; hasre=1; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { result[i][j] = mid[i][j]; } } }else if(counts == max_time){ int flag=0; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { if(result[i][j] > mid[i][j]) { break; flag=1; } } if(flag==1)break; } if(flag ==1) { hasre =1; for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { result[i][j] = mid[i][j]; } } } } } if(hasre ==0) { cout<<"IMPOSSIBLE"<<endl; continue; } for(int i=0;i<m;i++) { cout<<result[i][0]; for(int j=1;j<n;j++) { cout<<" "<<result[i][j]; } cout<<endl; } } return 0; }
最後附上一個網上大牛用該題寫的小遊戲
https://pan.baidu.com/s/1czj69yuvMVf_b7IbSOm-ig