網易內推編程題:異或運算求混合顏料的最小種類

矩陣的秩定義:是其行向量或列向量的極大無關組中包含向量的個數。

類似,顏料的最小種類等價於求由顏料組成的矩陣,求矩陣的的基的個數。

矩陣的秩求法:用初等行變換化成梯矩陣, 梯矩陣中非零行數就是矩陣的秩.

類似,基的求法是異或運算,而不是相加減。

基是類似與1,10,100,1000...這樣的數。如果顏色矩陣有1,10,100,1000四個數,則可以異或出0001~1111共15種顏色。

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

第一行爲繪製這幅畫需要的顏色種數n (1 ≤ n ≤ 50)
第二行爲n個數xi(1 ≤ xi ≤ 1,000,000,000),表示需要的各種顏料.


輸出描述:

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

3
1 7 3
輸出

3                                                                     */
/************************************************************************/

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

int GetBitLength(int k){
	int j = 0;
	while(k > 0){
		k >>= 1;
		++j;
	}
	return j;
}

int main(){
	int i, j, n;
	cin>>n;
	vector<int> v(n);
	for(i = 0; i < n; ++i){
		cin>>v[i];
	}
	sort(v.begin(), v.end());
	int res = 0;
	while(v.size() > 1){
		vector<int> xor_num;
		j = v.size() - 1;
		while(j > 0 && GetBitLength(v[j]) == GetBitLength(v[j - 1])){//倒數兩個數的最高位是否相同
			int xor_val = v[j] ^ v[j - 1];//最高位相同,則尋找能代表這麼高位的基
			if(xor_val != 0 && find(v.begin(), v.end(), xor_val) == v.end()){//異或結果在顏色矩陣裏存在,則可以去掉最大數,不受影響
				xor_num.push_back(xor_val);//異或結果不存在,則需保留異或結果,去掉最大數後,這個結果與次大數異或即可得到最大數
			}
			v.pop_back();//不管異或結果在顏色矩陣裏是否存在,都可以放心去掉最大數
			--j;
		}
		++res;//GetBitLength(v[j]) != GetBitLength(v[j - 1])時,最高位不同,則v[j]這顏料必須得買,否則這個最高位沒法異或出來
		v.pop_back();//v[j]最大數必須得買,res也計數了,可以放心得去掉v[j]
		if(xor_num.size() > 0){
			v.insert(v.end(), xor_num.begin(), xor_num.end());//既然把最大數給去掉了,爲了異或得到最大數,顏色矩陣需加進來之前算出的異或結果
			sort(v.begin(), v.end());
		}
	}
	cout<<res + v.size()<<endl;
	return 0;
}



發佈了26 篇原創文章 · 獲贊 15 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章