位元運算之ACM最佳化運用

來源:互聯網
上載者:User
文章來源http://hi.baidu.com/zfy0701/blog/item/6bd496894a77aeb60f244422.html#send
文章組織:
1、基本操作符
2、需要注意的問題
3、一些小應用
4、針對具體題目的應用
1> 搜尋類
2> 字串類
3> 其他類

基本操作符
與 &
或 |
異或 ^
左右移位 << / >>
取反 ~

需要注意的問題:
1、優先順序,這是個非常嚴重的問題,在進行位元運算的時候優先順序太容易被忽略掉了
尤其要注意的:
移位元運算符, 單目的取反運算子~的優先順序比比較子高。但是,&, |, ^的優先順序是比比較子低的!,這點一定要注意
如6 & 6 > 4的結果是0, 而不是 true; (6 & 6) > 4的結果才是true,所以要注意勤加括弧

2、速度
位元運算的速度是非常快的,你甚至可以忽略他的耗時,但是畢竟操作肯定是有耗損的。
所以,應該盡量使用
^=, |= ,&= 之類的操作,比如說a ^= b, 速度比 a = a ^ b快,因為前者是直接在a上進行操作,而 a = a ^ b的第二個a,是一個a 的副本,可見在操作中程式對a複製了一次,運算的結果又對原來的a做了一次賦值

3、範圍(要當心移位元運算時發生範圍溢出)

常用操作:
1、交換兩個元素的值:a ^= b ^= a ^= b,不用藉助第三個變數

2、不查表統計1的數量
int BitCnt(unsigned int n) {
int value = 0;
while (n) ++value, n &= n - 1;
return value;
}

3、迴圈位移
unsigned shift(unsigned now, int n, int N) { //n正表示左移,否則為右移
if (n > 0)
   now = (now >> (N - n)) | (now << n);
if (n < 0) {
   n = -n;
   now = (now << (N - n)) | (now >> n);
}
now &= base;
return now;
}

4、k位取反
a=~(~a^(a<<k))

優勢:
速度快,
節省空間的,又導致了速度快

POJ的題目上:

大類1:搜尋
此處不講題目,只講位元運算是怎樣在這些題中實現和應用的。由於搜尋題往往是基於對狀態的操作,位元運算往往特別有效,最佳化之後的效果可以有目共睹。

例1、POJ 1324
根據題目,確定了對狀態的表示之後(記錄目前狀態的蛇頭x, y值與剩下部分的運動狀態),一般容易想到剩下部分的運動狀態用一個數組(比如x[n-1], n為蛇節點數,n[0]為第二個節點的運動趨勢)去表示,且一個數組元素的值為0,1,2,3,即四個方向,蛇每次移動,這個方向數組需要更新一次,更新是很簡單的,除了n[0]更新之外,剩下的 n[i]等於上一輪的n[i-1](i>1);如果用數組,就必須用一個迴圈去更新它,這樣會導致程式速度不是很理想,所以可以想到用位元運算去類比,簡言之,就是把原來的一個數組壓縮的一個變數上去儲存,原來任何一個數組元素的值範圍0~3, 用二進位表示就是 00 ~ 11,最多佔用2位,這樣,我們就可以通過移位元運算,和或運算去實現所以操作。

基本技巧: 如果給你個一個方向序列 a0, a1, a2, a3, .... a(n-1),放到變數b中,且以最低位表示an,可以用如下迴圈
b = 0;
for(i=0; i<n; i++)
     b = (b<<2) | a[i];
即,每次把已經處理好的位段向上移兩位,這樣,在低位就會自動補齊兩個0,用一個 | 操作,就吧新的值給放進變數中了。

如果要從b中複原,則可使用 >> 的辦法

for(i=0; i<n; i++)
       a[n-1-i] = (b >> (i*2)) & 3; 
移位會將低位元素除掉,而 & 3則是把移到低位的元素取出。

更高效的方法是(兩種方法的前提都是不改變b的值)

t = b;
for(i=0; i<n; i++){
    a[n-1-i] = t & 3;
    t >>= 2;
}
高效的原因如文章開頭所述。

在表示狀態的位段操作中,最好將變數設為unsigned int (short)型,因為有符號型(負數的最高位(符號位)為1)的 >>操作加在負數上時會在右邊引入1而不是0, 這基本上不會是你想要的操作。

例2、POJ 3460 Booksort
這題可以在對書進行交換的時候應用位元運算,也許你認為用數組去類比更為直觀,但是看看下面的實現,也許你就不那麼認為了。
書最大編號15,
這樣就開一個64位整形,每4位表示一本書
首先預先處理,計算出兩張表
extract[i][j] 和 clear[i][j]分別表示把書架上第i到j本書取出或清空,顯然在i到j一段,位上全是1,而其他部分是0,而clear[i][j]就是extract[i][j]的取反

計算方法如下:

typedef unsigned long long longint;
const longint base = 15;//這是必須注意的,普通的常數15是整形,在以下的操作中會越界

for (i = 0; i < 15; i++) {
   extract[i][i] = base << (i * 4);
   clear[i][i] = ~extract[i][i];
   for (j = i + 1; j < 15; j++) {
    extract[i][j] = extract[i][j-1] | (base << (j * 4));
    clear[i][j] = ~extract[i][j];
   }
}
計算出這些以後,交換書就變得異常簡單

inline void transposition(longint &cur, longint &next, int &i, int &k, int &j) {//i,k段與k+1,c段置換
next = cur & clear[i][j];
next |= (cur & extract[i][k]) << ((j - k) << 2);
next |= (cur & extract[k+1][j]) >> ((k - i + 1) << 2);
}

先把i到j全部清空後的值賦給next,把 i, k段的書取出,移到高位(差值為(j - k) * 4),同理,再把k+i到j段的值取出移到低位。
如此清楚明了,而如果用數組的話,10+行的語句是少不了的,而且容易搞錯。

例3:HOJ 八數位問題
http://acm.hnu.cn:8080/online/?action=problem&type=show&id=10466
這題用位元運算我倒是沒有達到更快,空間稍微節省了些。
另外,這題的測試資料很強的說,贊一個。

用64位的整形去表示整個狀態,其中每4位表示一個數位(0~8),如果是用char數組,則用9個,用了72位。
取出某一位和清空某一位的掩碼事先要計算好
這樣做比用一個整形數如 123480567 之類的去表示更有優勢,因為顯然取出某一位的速度非常快,不需要 % 10, /10之類耗時的操作,如果這樣實現的話就不要用stl的map了,我無聊地試了次,相當之慢。還是老老實實康托展開的好。不過和開char數組的速度差不多的說(雖然說賦值時間大了,但畢竟別人是數組,呵呵,要是有每4位做一個單位的數組就好了——不要跟我說用struct裡面定義的位段啊,那相當的慢)。

最近還做了一個POJ 2286,可以用位元運算,但貌似有些麻煩,沒用,結果被一個用pascal的小子超在前面,哪天狀態好了要把這題改用位元運算去做,就不信刷不到 0ms.

更新中...

大類二:字串的hash與尋找

大家都知道Rabin-Karp演算法吧,其實Rabin-Karp實現後慢的一個原因是太多的模運算了,實際上,我們可以通過位元運算隱式地模數

原連結如下:http://www-igm.univ-mlv.fr/~lecroq/string/node5.html#SECTION0050

它開了一個int型,每次用移位代替乘法,又由於整形是有範圍的,但移位超過了範圍,效果就相當於做了一次 mod INT_MAX的操作。這樣改進後速度提高了一倍。

POJ 2513 Colored Sticks就可以考慮使用此種方法的hash,他的衝突也是非常小的。當然有更高效的的字串位元運算hash演算法,由於某些原因,我就不在這說了。

//待續

大類三:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.