题目描述
你就是一个画家!你现在想绘制一幅画,但是你现在没有足够颜色的颜料。为了让问题简单,我们用正整数表示不同颜色的颜料。你知道这幅画需要的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
题意:
给定了n种颜料,求至少需要几种颜料混合能得到这几种颜料。
给定了n个二进制数,将这些二进制进行异或,能得到最少几个不一样的二进制数。
思路:
1.每个二进制数作为一行,得到一个n行30列(2的30次方大于1,000,000,000)的矩阵。
2.因为s1 ^ s2 = s,能得到s ^ s1 = s2, s ^ s2 = s1。
3.题目就可以转化位求矩阵的秩。
题解:
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
int n;
vector<int> num;
int getHighBit(int num) {
int high = 0;
while (num != 0) {
high++;
num >>= 1;
}
return high;
}
int main() {
scanf("%d", &n);
num.resize(n);
for (int i = 0; i<n; i++) {
scanf("%d", &num[i]);
}
int first = n - 1;
int second = first - 1;
int result = 0;
//将数从小到大排列
sort(num.begin(), num.end());
while (num.size()>2) {
//如果最大值的最高位和次大值的最高位是一样的,可以进行异或
if (getHighBit(num[first]) == getHighBit(num[second])) {
int temp = num[first] ^ num[second];
//如果temp不等于数组中任意一个数时,加入数组
if (find(num.begin(), num.end(), temp) == num.end()) {
num.push_back(temp);
sort(num.begin(), num.end());
first++;
second++;
}
}
else {
result++;
}
//如果最高位相等,则最大值可以由次大值和temp生成,舍去。
//如果最高位不相等,则最大值已经不能用于合成其他值,因为其最高位大于其他数,result+1,舍去
num.pop_back();
first--;
second--;
}
printf("%d", result + 2);
return 0;
}