数据结构与算法
问题:
你就是一个画家!你现在想绘制一幅画,但是你现在没有足够颜色的颜料。为了让问题简单,我们用正整数表示不同颜色的颜料。你知道这幅画需要的n种颜色的颜料,你现在可以去商店购买一些颜料,但是商店不能保证能供应所有颜色的颜料,所以你需要自己混合一些颜料。混合两种不一样的颜色A和颜色B颜料可以产生(A XOR B)这种颜色的颜料(新产生的颜料也可以用作继续混合产生新的颜色,XOR表示异或操作)。本着勤俭节约的精神,你想购买更少的颜料就满足要求,所以兼职程序员的你需要编程来计算出最少需要购买几种颜色的颜料?
输入描述:
第一行为绘制这幅画需要的颜色种数n (1 ≤ n ≤ 50)
第二行为n个数xi(1 ≤ xi ≤ 1,000,000,000),表示需要的各种颜料.输出描述:
输出最少需要在商店购买的颜料颜色种数,注意可能购买的颜色不一定会使用在画中,只是为了产生新的颜色。输入例子:
3
1 7 3输出例子:
3
解答:
这个问题类似于线性代数中,求向量组的秩;
- 一个向量组中的一部分向量组成的最大线性无关向量组可以表示整个向量组.最大线性无关向量组所含向量的个数就是向量组的秩.
- 这里可以将 所有数的集合看成向量组, 每一个数(颜色)看成一个向量,把数的每个二进制位看成元素
- 向量组可以写成矩阵形式,矩阵的每一行就是一个数,求向量组的秩,就是求矩阵的秩,矩阵的秩可以通过消元法求出
#include<iostream>
using namespace std ;
//一个字节有8位,int占4个字节,所以一个整数占32位
#define BITNUM 8*sizeof(int)
#define MAXNUM 50
int c[MAXNUM] ;
int c_i[MAXNUM] ;//用于记录bits中哪几行不全为0
int now = 0 ;//用于记录c_i数组中有几个元素
int bits[MAXNUM][BITNUM] ;//矩阵,记录其二进制形式
/*
--------------------
将其转化为二进制矩阵
--------------------
*/
void trans_to_bit(int c[] ,int bits[][BITNUM] ,int n)
{
int p=1 ;
for(int i=0 ;i<n ;i++)
{
p=1 ;
for(int j=BITNUM-1; j>=0 ;j--)
{
bits[i][j] = (p&c[i])!=0 ? 1:0 ;
p= p<<1 ;
}
}
}
/*
----------------------------
高斯消元法对矩阵进行消元
----------------------------
*/
void max_linear(int bits[][BITNUM],int c_i[] ,int n)
{
int r ;//行数
int c ;//列数
int first = -1 ;
int i ;
r=c=0 ;
for( ; c<BITNUM ; c++)
{
r = 0 ;
first = -1 ;
for(; r<n ; r++ )
{
//如果是第一个出现为1的行
if( (bits[r][c]!=0) &&(first==-1))
{
int f = 0 ;
for(i=0 ;i<now ;i++)
{
if(r==c_i[i])
{
f=1 ;
break ;
}
}
if(f==0)
{
c_i[now++]=first = r ;
}
}//如果不是第一个出现的行
else if(bits[r][c]!=0)
{
for(i= 0 ; i<BITNUM ;i++)
{
//相同为0, 相异1
bits[r][i] = bits[r][i]^bits[first][i];
}
}
}
}
}
/*
----------------------------
主函数
----------------------------
*/
int main()
{
int n ;
int j,k ;
cin>>n ;
for(int i=0 ;i<n ;i++)
{
cin>>c[i] ;
}
trans_to_bit(c,bits,n) ;//转换
max_linear(bits,c_i,n) ;//消元
cout<<now;
return 0 ;
}