日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Fliptile (二进制压缩)

發(fā)布時(shí)間:2024/4/15 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Fliptile (二进制压缩) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目鏈接:http://poj.org/problem?id=3279

?

題目大意:有一個(gè)n*m的棋盤,0表示白色,1表示黑色。每次可以翻轉(zhuǎn)當(dāng)前位置,它的上下左右四個(gè)位置也會(huì)被相應(yīng)翻轉(zhuǎn)。問(wèn)最少翻轉(zhuǎn)多少次會(huì)使所有棋面顯示為白色,并給出需要翻轉(zhuǎn)的位置,0表示不翻轉(zhuǎn),1表示翻轉(zhuǎn)。

?

思路:第一行的翻轉(zhuǎn)狀態(tài)決定了你第二行的翻轉(zhuǎn)狀態(tài)。也可以說(shuō)第n-1行的翻轉(zhuǎn)狀態(tài)決定了第n行應(yīng)該如何去翻轉(zhuǎn)。? ? 所以我們可以說(shuō)第一行起到了決定性的作用

所以我們?nèi)ッ杜e第一行的所有的可能的情況。

?

這道題比較巧妙的地方就是它利用了二進(jìn)制壓縮,更加方便的去枚舉了第一行的每種情況。

?

首先讓我們來(lái)學(xué)習(xí)一下左移<<的概念,其實(shí)很好理解,就是將一個(gè)數(shù)轉(zhuǎn)換為二進(jìn)制,然后向左移動(dòng)若干位,然后在多出來(lái)的位置上補(bǔ)零,比如,對(duì)于5<<2,5的二進(jìn)制為101,左移兩位就是10100,那么最后的結(jié)果就是20,。?

利用這個(gè)特點(diǎn),我們可以通過(guò)使用一個(gè)特殊的數(shù)字1,來(lái)解決這個(gè)枚舉問(wèn)題。枚舉的第一步就是確定到底要改變哪幾位數(shù),聯(lián)想到二進(jìn)制,我們可以這樣處理,就題目的測(cè)試數(shù)據(jù)而言,一行有四個(gè)數(shù),用一個(gè)二進(jìn)制數(shù)xxxx表示,易知,xxxx一共有2^4種排列,其實(shí)也是1<<4,之所以這樣寫,是因?yàn)檫@比pow要快,所以,我們讓k從0開始枚舉到15,也就是0000到1111,然后規(guī)定,只要是帶1的位置,就要翻轉(zhuǎn)這個(gè)位置的數(shù)字,問(wèn)題又來(lái)了,怎么知道哪一位是1,呢,這里還是用到了二進(jìn)制,即與運(yùn)算,我們讓k分別與1000,0100,0010,0001進(jìn)行與運(yùn)算,分別對(duì)應(yīng)不同的位,如果結(jié)果不是1,說(shuō)明這一位上不是0,是不是灰常巧妙,當(dāng)然,那四個(gè)值依然是通過(guò)1的左移來(lái)計(jì)算出來(lái)的

具體代碼:

?

1 #include <iostream> 2 #include <string> 3 #include <cstring> 4 using namespace std; 5 6 int Map[20][20],cal[20][20],out[20][20]; 7 int n,m; 8 int dir[5][2] = {{0,0},{0,1},{0,-1},{1,0},{-1,0}}; 9 10 int fuc(int x,int y){ //(x,y)的狀態(tài)由本身的黑白 + 周圍五個(gè)的翻轉(zhuǎn)狀態(tài)決定 11 int temp = Map[x][y]; 12 13 for(int i = 0;i < 5;i ++){ 14 int xi = x+dir[i][0]; 15 int yi = y+dir[i][1]; 16 17 if(xi < 1 || xi > n || yi < 1 || yi > m) continue; 18 temp += cal[xi][yi]; 19 } 20 return temp%2; 21 } 22 int dfs(){ 23 for(int i = 2;i <= n;i ++) 24 for(int j = 1;j <= m;j ++) 25 if(fuc(i-1,j)) //如果上方為黑色,必須要翻轉(zhuǎn) 26 cal[i][j] = 1; 27 28 for(int i = 1;i <= m;i ++) //最后一行全白 29 if(fuc(n,i)) 30 return -1; 31 32 int res = 0; 33 for(int i = 1;i <= n;i ++) 34 for(int j = 1;j <= m;j ++) 35 res += cal[i][j]; 36 return res; 37 } 38 39 int main() 40 { 41 while(cin>>n>>m){ 42 for(int i = 1;i <= n;i ++) 43 for(int j = 1;j <= m;j ++) 44 cin>>Map[i][j]; 45 46 int flag = 0; 47 int ans = 0x3f3f3f3f; 48 for(int i = 0;i < 1<<m;i ++){ //第一行 1<<m種狀態(tài),二進(jìn)制從0開始,字典序從小到大 49 memset(cal,0,sizeof(cal)); 50 51 for(int j = 1;j <= m;j ++) //利用二進(jìn)制枚舉第一行所有的情況 52 cal[1][m-j+1] = i>>(j-1) & 1; // cal數(shù)組存貯的就是翻轉(zhuǎn)的情況了 53 int cont = dfs(); 54 if(cont >= 0 && cont < ans){ //翻轉(zhuǎn)次數(shù)最少 55 flag = 1; 56 ans = cont; 57 memcpy(out,cal,sizeof(cal)); 58 } 59 } 60 if(!flag) cout<<"IMPOSSIBLE"<<endl; 61 else{ 62 for(int i = 1;i <= n;i ++){ 63 for(int j = 1;j <= m;j ++){ 64 if(j != 1) cout<<" "; 65 cout<<out[i][j]; 66 } 67 cout<<endl; 68 } 69 } 70 } 71 return 0; 72 }

?

轉(zhuǎn)載于:https://www.cnblogs.com/-Ackerman/p/11186485.html

總結(jié)

以上是生活随笔為你收集整理的Fliptile (二进制压缩)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。