POJ - 3279 Fliptile(状态压缩+位运算+暴力)
題目鏈接:點擊查看
題目大意:給出一個n*m的01矩陣,為了好描述,我們設0和1是兩個相反的狀態,我們的目標是要將整個矩陣全部變成1,現在我們可以將某一個點(x,y)更改為相反的狀態,不過相應的該點周圍的四個點(x+1,y),(x-1,y),(x,y+1),(x,y-1)也都需要變為其本身相反的狀態,問若想要滿足條件最少需要操作多少次,并輸出方案
題目分析:今天看大藍書位運算的時候看到了一個簡單版本的題目,直接給秒了,不過癮,想起來之前在poj上做過一個很類似的稍難點的題目,也就是現在這道了,當時卡了我好久,最后還是面向題解編程才寫出來的,現在再回顧一下這給題目直接就給秒了,感覺真的太爽啦
回到這個題目上,若我們固定了第一行之后(不能再改變第一行了),則滿足題意的方案至多只有1種,其原因是:當第i行某一位為0時,若前i行已經被固定,只能點擊第i+1行該位置上的數字才能使第i行的這一位變為1,從上到下按照行依次傳遞就能得到方案了,又因為n和m最大只有15,我們可以直接對列狀態壓縮,首先枚舉第一行的所有狀態,至多有2^m次方種情況,其中二進制中的1表示翻轉該方塊,0表示不翻轉該方塊,當確定好第一行的狀態后,不斷向下傳遞狀態就好了,判斷一下最后一行的狀態能不能滿足條件,若可以的話嘗試更新最小值,并用一個數組記錄一下答案,最后輸出答案就好了,總的時間復雜度是n*2^m,這個題目為了迎合題意以及簡化操作,自己寫了不少函數,用起來還是挺方便的
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;int n,m;int maze[20][20],temp[20][20],temp2[20][20],ans[20][20]; //maze:維護初始矩陣 temp:每次處理時暫時用到的副本矩陣 temp2:記錄每次答案用的 ans:記錄最小值的答案void _copy(int s[][20],int t[][20])//將t數組復制給s數組 {for(int i=0;i<n;i++)for(int j=0;j<m;j++)s[i][j]=t[i][j]; }bool check(int a[])//檢查某一行的狀態是否全部為1 {for(int i=0;i<m;i++)if(a[i])return false;return true; }void solve(int a[][20],int x,int y)//改變當前方塊以及四周方塊的狀態 {a[x][y]^=1;if(x-1>=0)a[x-1][y]^=1;if(y-1>=0)a[x][y-1]^=1;if(x+1<20)a[x+1][y]^=1;if(y+1<20)a[x][y+1]^=1; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);while(scanf("%d%d",&n,&m)!=EOF){for(int i=0;i<n;i++)for(int j=0;j<m;j++)scanf("%d",&maze[i][j]);int mmin=inf;//維護最小方案數for(int i=0;i<1<<m;i++)//枚舉2^m種情況{int cnt=0;//記錄當前方案數_copy(temp,maze);memset(temp2,0,sizeof(temp2));for(int j=0;j<m;j++)//維護第一行{if(i>>j&1){solve(temp,0,j);temp2[0][j]=1;cnt++;}}for(int i=1;i<n;i++)//逐層向下轉移狀態for(int j=0;j<m;j++){if(temp[i-1][j]){solve(temp,i,j);temp2[i][j]=1;cnt++;}}if(check(temp[n-1]))//檢查最后一行{if(mmin>cnt)//嘗試更新最小值{mmin=cnt;_copy(ans,temp2);}}}if(mmin==inf)printf("IMPOSSIBLE\n");else{for(int i=0;i<n;i++){printf("%d",ans[i][0]);for(int j=1;j<m;j++)printf(" %d",ans[i][j]);printf("\n");}}}return 0; }?
總結
以上是生活随笔為你收集整理的POJ - 3279 Fliptile(状态压缩+位运算+暴力)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (转)快速统计二进制中1的个数
- 下一篇: POJ - 1958 Strange T