1. 程式人生 > 實用技巧 >1094: 有多少位是1

1094: 有多少位是1

題目連結:http://oj.ecustacm.cn/problem.php?id=1094

時間限制: 1 Sec 記憶體限制: 256 MB
題目描述
把一個正數轉成二進位制數後,各位數字分別是0或1,請你程式設計統計有多少位是1。
如11的二進位制數是1011,共有三位是1。
輸入
輸入有若干行,每行一個正整數,數字不超過10^18。
輸出
對應輸出二進位制數的1的個數。
樣例輸入 Copy
11
1
721
樣例輸出 Copy
3
1
5
來源/分類
基礎題 數論

題意:就是求一個二進位制數有多少個一
思路:用簡單好理解的直接轉為二進位制統計一的個數,或者用與運算來做。以下提供三種題解。

法一: 將原數字轉為二進位制,在此過程統計1的個數


這個方法不用多說,就是轉換過程中多加個判斷語句統計下即可

程式碼:

 1 num=0;
 2 long long m=n;  // 法一: 將原數字轉為二進位制,在此過程統計1的個數
 3 while(m!=0)            
 4 {
 5      int t=m%2;
 6      if(t==1)
 7          num++;
 8       m/=2;
 9 }
10 cout<<num<<endl;      

法二: 將原數字(二進位制)一直往右移動 與 1 進行 與運算
舉個例子,比如數字5,二進位制表示為101(忽略前面的0),
101往不斷右移,每次都與1進行與運算,如果結果等於1就說明存在一個1,直到移動64位後停止(因為題目給的數量級是:數字不超過10^18,所以用long long)然後統計個數就可以了


101(原數字,也就是右移0位後的數字)
001(1)

001 相與的結果等於1(num++)
---------------------------------------------------------
010 (右移1位後的數字)
001(1)

000 相與的結果不等於1
---------------------------------------------------------
001 (右移2位後的數字)
001 (1)

001 相與的結果等於1(num++)
---------------------------------------------------------
001再右移就變成000了(所以到這也就把所有的1統計完了)

000 (右移3位後的數字)
001 (1)

000 相與的結果不等於1


程式碼:

1 num=0;
2 for(int i=0; i<64; i++) // 法二: 將原數字(二進位制)一直往右移動 與 1 進行 與運算
3 {
4      if(((n>>i)&1)==1)
5      num++;
6 }
7 cout<<num<<endl;

法三: 每次消掉最後面的那個1
這個很巧妙,就是讓n=((n-1)&n),直到n==0停止,這個過程中每次就可以消掉最右邊的那個1
還用5舉例 101
101 (n)
100 (n-1)

100 相與的結果等於100,沒跳出迴圈num++
然後n=100了
---------------------------------------------------------
100 (n)
011 (n-1)

000 相與的結果等於100,此時還沒跳出迴圈num++
n=0了,跳出迴圈了,結束。


程式碼:

1 num=0;
2 while(n!=0) // 法三: 每次消掉最後面的那個1
3 {
4      n=((n-1)&n);
5      num++;
6 }
7 cout<<num<<endl;

完整程式碼:

 1 #pragma GCC optimize(2)
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<map>
 8 #include<stack>
 9 #include<set>
10 #include<vector>
11 #include<queue>
12 #include<iomanip>
13 #include<bitset>
14 using namespace std;
15 int main()
16 {
17     long long n,x;
18     long long num=0;
19     while(cin>>n)
20     {
21         num=0;
22         long long m=n;  // 法一: 將原數字轉為二進位制,在此過程統計1的個數
23         while(m!=0)
24         {
25             int t=m%2;
26             if(t==1)
27                 num++;
28             m/=2;
29         }
30         cout<<num<<endl;
31 
32         num=0;
33         for(int i=0; i<64; i++) // 法二: 將原數字(二進位制)一直往右移動 與 1 進行 與運算
34         {
35             if(((n>>i)&1)==1)
36                 num++;
37         }
38         cout<<num<<endl;
39 
40         num=0;
41         while(n!=0)    // 法三: 每次消掉最後面的那個1
42         {
43             n=((n-1)&n);
44             num++;
45         }
46         cout<<num<<endl;
47 
48     }
49     return 0;
50 }

任取一種方法即可

加油!

共同努力!

Keafmd