你就是一个画家!你现在想绘制一幅画,但是你现在没有足够颜色的颜料。为了让问题简单,我们用正整数表示不同颜色的颜料。你知道这幅画需要的n种颜色的颜料,你现在可以去商店购买一些颜料,但是商店不能保证能供应所有颜色的颜料,所以你需要自己混合一些颜料。混合两种不一样的颜色A和颜色B颜料可以产生(A XOR B)这种颜色的颜料(新产生的颜料也可以用作继续混合产生新的颜色,XOR表示异或操作)。本着勤俭节约的精神,你想购买更少的颜料就满足要求,所以兼职程序员的你需要编程来计算出最少需要购买几种颜色的颜料?
输入描述:
第一行为绘制这幅画需要的颜色种数n (1 ≤ n ≤ 50)
第二行为n个数xi(1 ≤ xi ≤ 1,000,000,000),表示需要的各种颜料.
输出描述:
输出最少需要在商店购买的颜料颜色种数,注意可能购买的颜色不一定会使用在画中,只是为了产生新的颜色。
牛客网的解题报告:点击打开链接
解题报告挺赞的,不过看完后其实就是求 高等代数 里有关向量组的 秩问题,更加严格的证明可以参阅书本里的相关内容。
不过代码写的感觉挺糟糕的,在网上找了一下,全部的代码都弄得更高斯消元似的,复杂度都达到了O(n*n*32),就是说都一位一位的进行位运算...
实际上直接对n个整数两两做位运算即可。判断最高位也不用判断,直接找最大值即可,而且判断是否做位运算也是一样。
所以实际时间复杂度只要O(n*n)即可,空间复杂度O(n)。
混合颜色
分析:
这题是最难的一个题目,需要不错的分析能力和一定的数学基础。 首先解释下异或操作:
(1,1,0,0)
(1,0,1,0)
——————
(0,1,1,0)
对于每个独立的位,其实我们相当于在做一个mod 2的运算,于是我们可以把每个数抽象为一个二进制数的向量。
然后来解释一下样例: 你可以购买1,2,4这三种颜料,1已经有了,3可以通过由 1 XOR 2 = 3得到,7可以通过1 XOR 4 = 5,5 XOR 2 = 7 得到,所以最少为3种
想象一下对于两个给定的数(向量),他们可以生成的新的数,本质就是两个向量的所有线性表示。因为此处实际是在做一个mod 2的操作,那么线性表示的系数就是0或1。 于是原问题就抽象为,给定一些向量(数)组成的向量空间,增加一个最小的向量集合,使向量的线性组合都可以生成向量空间中的所有向量。这个叫做向量空间的基。
怎么算出这个基呢?线性代数里面我们都学过:可以对原来所有向量组成的矩阵用高斯消元法直到让剩余的向量都是线性无关的,非0向量的个数就是答案。
这是我的AC代码:
#include<iostream>
using namespace std;
#define maxlen 1000000
int a[maxlen];
int main()
{
int n, mymax_index = 0;
cin >> n;
for (int i = 0; i < n; ++i)
{
cin >> a[i];
if (a[mymax_index] < a[i])
{
mymax_index = i;
}
}
int tmp, i;
for (i = 0; i < n; ++i)
{
if (mymax_index != i)
{
tmp = a[i]; a[i] = a[mymax_index]; a[mymax_index] = tmp; //最大值交换
// cout << mymax_index<<endl;
}
if (0 == a[i])
{
cout << i << endl;
return 0;
}
for (int j = mymax_index = i + 1; j < n; ++j)
{
if (a[j])
{
tmp = a[j] ^ a[i];
if (tmp < a[j]) //只对当前最高位为1的进行异或操作
{
a[j] = tmp;
}
if (a[mymax_index] < a[j]) //找最大值
{
mymax_index = j;
}
}
}
}
cout << n << endl;
return 0;
}
代码的时间复杂度O(n*n),空间复杂度O(n)。
现在问题在于是否存在更优的时间复杂度的算法。
最近又做了一道有关XOR的与秩相关的题目,回过头来看此题,发现之间的时间复杂度分析错了。
实际上,由于XOR的rank只跟数的bit数有关。因此该题中最多rank不会超过32。
所以实际代码运行效率,时间复杂度是线性的,即为O(maxbitsize * n),可以算是线性的了。
还能有更好的方法么?避免maxbitsize?