網易筆試編程題-混合顏料

題目描述:你就是一個畫家!你現在想繪製一幅畫,但是你現在沒有足夠顏色的顏料。爲了讓問題簡單,我們用正整數表示不同顏色的顏料。你知道這幅畫需要的n種顏色的顏料,你現在可以去商店購買一些顏料,但是商店不能保證能供應所有顏色的顏料,所以你需要自己混合一些顏料。混合兩種不一樣的顏色A和顏色B顏料可以產生(A XOR B)這種顏色的顏料(新產生的顏料也可以用作繼續混合產生新的顏色,XOR表示異或操作)。本着勤儉節約的精神,你想購買更少的顏料就滿足要求,所以兼職程序員的你需要編程來計算出最少需要購買幾種顏色的顏料?
輸入描述:
第一行爲繪製這幅畫需要的顏色種數n (1 ≤ n ≤ 50)
第二行爲n個數xi(1 ≤ xi ≤ 1,000,000,000),表示需要的各種顏料.

輸出描述:
輸出最少需要在商店購買的顏料顏色種數,注意可能購買的顏色不一定會使用在畫中,只是爲了產生新的顏色。

輸入例子:
3
1 7 3

輸出例子:
3
做法類似於求用初等行變換來求矩陣的秩。要得到唯一的顏料數字個數,就是求出該矩陣線性無關的基底個數,即秩。將每個數字按照從小到大排列,他們的二進制形式可以看成是一個矩陣,比如1,7,3這三個數字,首先從小到大排列:1,3,7。將他們用二進制表示即爲
0001
0011
0111,
官網給的這個例子不好,因爲這個矩陣不需要初等行變換就能得到它的秩爲3,爲此,我們重新造一組輸入用例:1, 2, 3, 6, 7, 8, 13。雖然很簡單,但能說明問題就好,他們的二進制表示爲:
第一行:0001
第二行:0010
第三行:0011
第四行:0110
第五行:0111
第六行:1000
第七行:1011
我們從前往後進行掃描(當然也可以從後往前開始掃描),在這個矩陣中,第二行和第三行最高位可以消除,經過異或,消除最高位,即得到0001,判斷該數字在矩陣中是否存在,如果存在,就不插入;第四行和第五行可以消除,經過異或,消除最高位,即得到0001,判斷該數字在矩陣中是否存在,如果存在,就不插入;第六行和第七行可以消除,經過異或,消除最高位,得到0011,判斷該數字在矩陣中是否存在,若存在,就不插入。
因爲我們是要求出基數的個數,所以對於高位相同的兩個數字,我們可以刪除一個,保留該種類的基數存在一個即可。得到的結果爲:
第一行:0001
第二行:0010
第三行:0110
第四行:0011
重新進行排序有:
第一行:0001
第二行:0010
第三行:0011
第四行:0110
繼續對相鄰兩行進行異或操作,得到:
第一行:0001
第二行:0010
第三行:0110
因此,得到該矩陣的秩:3,也就是說,數字1, 2, 3, 6, 7, 8, 13,可有三個數經過異或得到,這三個數可以是:1,2,6,也可以是其他(其他可能是由於選擇刪除兩個高位相同的數字不同而得到不同的數字)。
算法描述:
首先讀入元素並存入動態數組vector中,並 對元素從小到大進行排序。開始循環, 定義while循環條件,當動態數組元素個數大於2時,繼續循環(因爲若要進行顏料混合,最少需要2個,當動態數組的元素少於2個時,就不用進行初等行變換了,即不需要顏色混合了),在循環體外定義了兩個下標分別指向動態數組倒數第一個和倒數第二個,判斷下標所指向的數字最高位1的位置是否相同,如果相同,則進行異或操作,再判斷得到的新值是否在數組中,如果不在,則將新值插入動態數組中,再對其進行排序。如果下標所指向的數字最高位1的位置不同,則計數器加一,將動態數組最後一個元素彈出,兩個下標上移(自減)。重複這個過程,直到循環結束,輸出動態數組中元素個數(其實是2)+ 計數器值即得到顏料數字基的個數,也就是秩的大小。
程序代碼如下:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int theNumOfOne(int num);

int main(void)
{
    int n;
    cin >> n;
    vector<int> nums;
    while (n--)
    {
        int temp;
        cin >> temp;
        nums.push_back(temp);
    }
    sort(nums.begin(), nums.end());
    int rank = 0;
    int theLastOne = nums.size() - 1;
    int uperOfTheLastOne = theLastOne - 1;
    while(nums.size() > 2)
    {
        if (theNumOfOne(nums[theLastOne]) == theNumOfOne(nums[uperOfTheLastOne]))
        {
            int newNum = nums[theLastOne] ^ nums[uperOfTheLastOne];
                        if (find(nums.begin(), nums.end(), newNum) == nums.end())
                        {
                                nums.push_back(newNum);
                                sort(nums.begin(), nums.end());
                                theLastOne ++;
                                uperOfTheLastOne ++;
                        }
        }
        else
        {
            rank ++;
        }
        nums.pop_back();
        theLastOne --;
        uperOfTheLastOne --;
    }
    cout << rank + 2 << endl;
    return 0;
}

int theNumOfOne(int num)
{
    int cnt = 0;
    while(num)
    {
        cnt ++;
        num >>= 1;
    }
    return cnt;
}

若有錯誤之處,敬請指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章