首页 > 试题广场 >

混合颜料

[编程题]混合颜料
  • 热度指数:12836 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
你就是一个画家!你现在想绘制一幅画,但是你现在没有足够颜色的颜料。为了让问题简单,我们用正整数表示不同颜色的颜料。你知道这幅画需要的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
这道题小白表示理解起来很困难,结合了@我要变橙色和@夕阳Co'de的解题思路后,将再进一步的自己的理解写在下面:

题目翻译理解

ok,这道题翻译过来,就是进行多次输入,每次输入n个数,将这些数之间进行多次xor(异或操作),其中一个数可能被xor多次,看最后能剩余多少不重复的数,输出数量即可。

解题思路

在C++中,将两个数进行xor,用的是^符号,但是实际上是将十进制转换为二进制之后,再进行xor,这样,这n个十进制的数,就被转换成了n个二进制的包含1,0的字符串,将每个数转换成二进制之后单成一行,位数小的前面被补全0,这样这n个数就变成了n行矩阵,由于1 ≤ xi ≤ 1,000,000,000,而2的30次幂是10亿多,所以这个矩阵最大是n*30的矩阵。

现在将这个矩阵列出来,如:

101010
111010
101101
110110

然后进行行与行之间的xor,其中1^1=0;  0^0=0;  1^0=1; 0^1=1;
有没有发现这种运算很像求矩阵的秩?相同的相减为0,不同的相减为1.

矩阵的秩定义:是其行向量或列向量的极大无关组中包含向量的个数。
矩阵的秩求法:用初等行变换化成梯矩阵, 梯矩阵中非零行数就是矩阵的秩.

所以这道题就被转化成了求矩阵的秩, 求法如下。

//

//  main.cpp

//  NiuKe_HunHeYanLiao

//

//  Created by 麦心 on 16/8/18.

//  Copyright © 2016 程序工匠 0_0 小姐 . All rights reserved.

//

#include <iostream>

using namespace std ;

#include <vector>

#include <algorithm>

// 求一个数的二进制的最高位是哪位

int getHighBit( int num){

    int highbit = 0 ;

    while (num) {

        // 将该数的二进制右移一位

        num>>= 1 ;

        highbit++;

    }

    return highbit;

}

int main() {

    vector < int > colors;

    int n;

    

    while ( cin >> n){

        colors. clear ();

        int result = 0 ;

        int temp;

        int i = n;

        while (i--) {

            cin >>temp;

            colors. push_back (temp);

        }

        

        // colors 进行从小到大的排序

        sort (colors. begin (), colors. end ());

        int bigger, smaller;

        //bigger smaller 始终指向的是最后一位和倒数第二位数

        bigger = n - 1 ;

        smaller = bigger - 1 ;

        

        while (colors. size ()> 2 ) {

            // 如果两者的最高位相同,说明最高位可以消掉,

            // 将两者 xor ,或者说将矩阵两行相减消掉最高位

             if ( getHighBit (colors[ bigger ]) == getHighBit (colors[ smaller ])){

                int tem = colors[ bigger ]^colors[ smaller ];

                //find 函数头文件是 <algorithm>

                // 泛型算法的 find ,在非 string 类型的容器里,可以直接找出所对应的元素

                // vector 的头开始一直到尾,找到第一个值为 temp 的元素,返回的是一个指向该元素的迭代器 std::vector<int>::iterator 类型

                

                // 因为现在 xor 的是两个最大的数,而且最高位已被消掉,所以 xor 得到的结果一定比这两个数小

                

                // 如果 temp 这个 比最大两个数小的 数没有被找到,则将 temp 加到 colors 数组中,进行再次 xor

                // 找不到的话,返回 colors.end 应该是固定用法

                if ( find (colors. begin (), colors. end (), tem)==colors. end ()){

                    colors. push_back (tem);

                    sort (colors. begin (), colors. end ());

                    bigger++; // 因为 colors 中多了一个数,所以需要位数+ 1

                    smaller++;

                }

            } else {

                result++;

            }

            // 如果两者最高位不同,说明已经所有数的最高位已经只有最大的那个数是 1 了,这样它已经不可能被消掉了,结果+ 1

            

            // 如果两个最大数的最高位可以消掉,那么消除之后,最大数已被消掉,没有用了

            // 如果两个最大数的最高位不可以消掉,那么结果+ 1 ,最大数也没有用了。

            // 弹出最大数

            colors. pop_back ();

            

            // 因为弹出了一个数,所以 bigger smaller 都要相应- 1

            bigger = smaller;

            smaller--;

        }

        cout <<result+2 << endl ;

    }

}



理解完毕,不对之处还请大神指出,谢谢。
编辑于 2016-08-18 16:22:58 回复(11)
和线性代数里求线性方程组差不多,通过线性变换求极大线性无关组。而题目把“线性变换”改成了“异或变换”,原理是一样的,就是求一组能表示所有颜色的“基”,最后保留一个上三角矩阵。一个数是由32位表示的,那么我们可以把一个数看成是32维空间的一个向量。最后形成了一个n*32的矩阵,然后就可以按照我们线性代数的方法进行变换啦,变成上三角矩阵,最后剩几行就是需要几种颜色。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>

using namespace std;
//求该数最高位是第几位
int getHighPosition(int a){
	int count = 0;
	while (a){
		a >>= 1;
		count++;
	}
	return count;
}
int main(){
	int n;
	vector<int> colors;
	while (cin>>n)
	{
		int temp;
		int res=0;
		int i = n;
		colors.clear();
		while (i--){
			cin >> temp;
			colors.push_back(temp);
		}
		sort(colors.begin(), colors.end());
		//endValue和cmpValue指向最后一个数和倒数第二个数
		int endValue = n-1;
		int cmpValue = endValue - 1;
		//两种颜色以上才有混合的可能,如果只需要两种颜色,那么最少就要购买两种,购买一种是不可能得到两种颜色的。
		while (colors.size()>2)
		{
			//只有最高位相同,那么他们的最高位一定可以消去
			if (getHighPosition(colors[endValue]) == getHighPosition(colors[cmpValue]))
			{
				
				int temp = colors[endValue] ^ colors[cmpValue];
				//如果异或出来的这个低维的颜色没有,就加入到colors里
				if (find(colors.begin(), colors.end(), temp) == colors.end())
				{
					colors.push_back(temp);
					sort(colors.begin(), colors.end());
					//因为新加入了一个数,所以为了让endValue和cmpValue还是指向倒数第一和倒数第二个数,需要++
					endValue++;
					cmpValue++;
				}
			}
			else
			{
				res++;
			}
			//每判断完一次,就把最后一个数扔掉,没什么用了
			colors.pop_back();			
			endValue = cmpValue;
			cmpValue--;	
		}
		cout << res + colors.size() << endl;

	}


}


发表于 2016-08-16 10:48:31 回复(2)
参考几位大佬的答案,按自己的理解备注了下~~
代码思路补充:的最大两个数最高位不同(也即最左边1的位数不同),则大的最左边位置为1,小的相应位为0,显然最大的是不能被合成的(除自己外,再没有相应位为1的啊),而且它也不能合成其它数(其它数相应位都为0啊),故此时将最大数直接丢弃,所需的颜料数加一。若最高位相同,则对两数异或,合成的数(一定比当前合成它的两数小)若不存在,则添加入初始颜料数中并排序(以待合成其它数),无论合成的数是否存在,都要删掉最后一个数,因为它是可以被合成的(A(最大)^B(次大)=C(合成数),B^C=A(最大数))。总之最后一个数(排序后)每比操作一次都要舍弃掉
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int maxHighPos(int);
int main(void)
{
int colorNum = 0;
while (cin >> colorNum) {
vector<int>iVec(colorNum, 0);//所需的颜料
for (int i = 0;i < colorNum;++i)
cin >> iVec[i];
int kinds = 0;
sort(iVec.begin(), iVec.end());
int maxIndex = colorNum - 1, nextMaxIndex = colorNum - 2;//最大值、次大值下标
while (iVec.size() > 2) {//颜料数大于2才能合成
if (maxHighPos(iVec[maxIndex]) == maxHighPos(iVec[nextMaxIndex])) {
int tmp = iVec[maxIndex] ^ iVec[nextMaxIndex];//合成的颜料
if (find(iVec.begin(), iVec.end(), tmp) == iVec.end()) {//该颜料不在当前容器中
iVec.push_back(tmp);
sort(iVec.begin(), iVec.end());
++maxIndex;
++nextMaxIndex;
}
}
else {
++kinds;//最高位位数不同(最高位对应的1只有自己),该最大颜料不能被合成,也不能合成其它颜料
}
iVec.pop_back();//每次操作完将最大数丢弃(要么能被合成(A^B=C,A=B^C),要么不能合成其它颜料)
--maxIndex;
--nextMaxIndex;
}
cout << kinds + iVec.size() << endl;
}
return 0;
}

int maxHighPos(int num)
{
int iRet = 0;
while (num) {
++iRet;
num >>= 1;//右移一位自赋值
}
return iRet;
}
发表于 2017-08-21 16:24:00 回复(0)
'''
    说明:以下代码和思路均是参考各位大神,
    本人只做了额外的总结和解释,帮助大家理解。
    
    问题理解:
    输入n个数,将这些数之间进行多次xor(异或操作),
    其中一个数可能被xor多次,看最后能剩余多少不重复的数,输出数量即可。
    
    思路:
    类似矩阵求秩:首先将各数从大到小排序,
    对位数与该行相同的进行异或操作,操作结束后该行就“独立”了。
    
    具体过程如下:
        排序 i=0      异或      排序 i=1    异或
    101010 --> 111010 --> 111010 --> 111010 --> 
    111010 --> 110110 --> 001100 --> 010111 --> 
    101101 --> 101101 --> 010111 --> 010000 --> 
    110110 --> 101010 --> 010000 --> 001100 --> 

        排序 i=2   排序 i=3    排序 i=4 end     
    111010 --> 111010 --> 111010 --> 111010     
    010111 --> 010111 --> 010111 --> 010111     
    000111 --> 001100 --> 001100 --> 001100     
    001100 --> 000111 --> 000111 --> 000111     
    '''

# 求数字转化为2进制后的位数
def getHiBit(n):
    ans = 0
    while n:
        ans += 1
        n >>= 1
    return ans

n = int(input())
colors = list(map(int, input().split()))
colors.sort(reverse=True) # 从大到小排序
i = 0
while i<n and colors[i]:
    hibit = getHiBit(colors[i])
    for j in range(i+1, n):
        if getHiBit(colors[j])==hibit:
            colors[j] ^= colors[i]
        else: break
    colors.sort(reverse=True)
    i += 1
print(i)

编辑于 2018-08-07 16:30:28 回复(0)
参照 夕阳Code,程序工匠0_0小姐思路
def getHiBit(n):
    ans = 0
    while n:
        ans += 1
        n >>= 1
    return ans
n = int(input())
colors = list(map(int, input().split()))
colors.sort(reverse=True)
i = 0
while i<n and colors[i]:
    hibit = getHiBit(colors[i])
    for j in range(i+1, n):
        if getHiBit(colors[j])==hibit:
            colors[j] ^= colors[i]
        else: break
    colors.sort(reverse=True)
    i += 1
print(i)  

编辑于 2017-10-08 21:48:02 回复(0)
我是写不出来的,@loolroco这位仁兄的代码很巧妙,但是没写注释。
我就写一下他的思路吧(如果写错了,勿怪)。
本质上还是一种消元法,每次消除最高位。
如:(已经表示成二进制,逆序)
1110
1101
1011
0111
则首先对最高位不为零的数,挨个进行异或,异或能找出两个数不同的地方,比如
1110^1101=0011,即这两个数最后两位不一样。将这种差异(异或为0则相同,不记录)记录下来并且删除原来的那个数,保存并加入原来的color数组中,用set去除重复(有可能某些数异或结果是一样的,比如1001^1010=1110^1101=0011),继续迭代直到位数最多的数遍历完。
因为最高位均为1,所以他们异或之后,必然能全部消除最高位,记录的颜色数目+1,然后更新color数组,sort后,又从后往前迭代。
当最后colors的个数小于等于2(我觉得个数小于2退出应该也可以吧。。。也许他是觉得这样处理方便吧)即退出迭代。后面是我参照他的思路写的。。
#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;
        v.pop_back();
        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;
}

编辑于 2016-08-08 21:39:20 回复(0)

参看了多位大佬的代码,这里思路就先不特别详细的讲。
这题求矩阵的秩,但我是个数学渣渣,这里就先不讲秩这个概念了。
记得初中学过的多元一次方程组吗? 那么如果把每种颜料看做一个方程,数值上的每一位看做一个变量,那么整个输入就是个方程组。
我们所要作的就是找到最少方程去解这个方程组, 所以大家肯定会想到高斯消元。(数学渣渣不知道什么叫做高斯消元)。
那么用初中生的做法就是,有目的性的消元,比如一个三元一次方程组,那么计算过程就会是:首先消掉某一个未知数(比如x),然后再消掉另外一个未知数(y),最后就只剩z,那么题目就解出来了。
放到我们这个题目中,会变成这样,找到最高位置的变量(比如x),然后将其他的数中含有该变量(x)的方程全部消掉。然后是次高位。。。。。。第0位。(在此过程中,中间结果相同的数最后都会被异或成0)。
最后统计不为0的数的个数,即为所求解。

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

int get_high_point(int number)
{
int count = 0;
while (number > 0)
{
number >>= 1;
count++;
}
return count;
}
int main()
{
int n;
cin >> n;
vector<int> array(n);
int sum = 0;
for (int i = 0; i != n; i++) cin >> array[i];
sort(array.begin(), array.end());
for (int i = n - 1; i > 0; i--)
{
for (int j = i - 1; j >= 0; j--)
{
if (get_high_point(array[i]) == get_high_point(array[j]))
array[j] = array[i] ^ array[j];
}
sort(array.begin(), array.end());
}
for (int i = 0; i != array.size(); i++)
{
if (array[i] != 0)
sum++;
}
cout << sum << endl;
return 0;
}
发表于 2017-08-30 16:48:02 回复(0)
解题思路时参考NotDeep的设计而写。

把每个数字想成一个矩阵的行,经过高斯消去,最后得到矩阵的秩即为最后结果。
l ----- 表示行   n-----表示第几行  ai -----表示这个行有多少个

矩阵中经过高斯消去,每一行都可以表示为  ln = a1*l1 +a2*l2+·······+a(n-1)*l(n-1);
这样就好理解一点。
发表于 2016-08-08 13:07:41 回复(2)
import java.util.*;
import java.io.*;
public class Main {
    /**
    *矩阵论中的知识表明,最大线性无关组是解的最基本的形式。
    *这个题目类似于求矩阵的最大线性无关组,用高斯消元法就可以了,正向算一遍即可,反向不用计算(我们只关心无关组的向量个数,不关心具体解的形式)。
    *多元方程,我们从左到右不为零开始消元,对于二进制数,那就是从大的数开始就可以了。
    *用一个函数判断每一位是否为零,为零才消元。遍历的时候注意方程有几个,我们每次遍历的目标是消灭一列的1,使每一列最多1个一,
    *但是方程不够的时候,就不必向下消了,已经可以结束了。
    */
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine().trim());
        int[] arrColor = new int[n];
        String[] arrInput = br.readLine().trim().split(" ");
        for (int i=0; i<n; i++) {
            arrColor[i]  = Integer.parseInt(arrInput[i]);
        }
        Arrays.sort(arrColor);//排序
        int computLoopCnt = 0;//记录循环的个数
        for (int i=31; i>=0; i--) {//遍历每一位,最大的数的该位为零就跳过
            int row = (n - 1) - computLoopCnt;
            if (row <= 0) {//如果行数不够了,直接停止
                break;
            }
            if (isNbitIsOne(arrColor[row],i)) {//判断该为是否为零
                computLoopCnt++;
                for (int j=row-1; j>=0; j--) {
                    if (isNbitIsOne(arrColor[j],i)) {
                        arrColor[j] = arrColor[row] ^ arrColor[j];
                    }
                }
                Arrays.sort(arrColor, 0, row );//每次计算后排序,因为异或后可能变大,要正确找到最大的
            }
        }
        int baseNum = 0;
        for (int i=0; i<n; i++) {
            if (arrColor[i] != 0) {
                baseNum++;
            }
        }
        System.out.println(baseNum);
    }
    public static boolean isNbitIsOne(int a, int n) {//判断第n位(顺寻方向:自右向左)是否为零
        if (n > 32) {
            throw new IllegalArgumentException();
        }
        int test = 1 << n;
        boolean isOne = false;
        if (test == (a & test)) {
            isOne = true;
        }
        return isOne;
    }
}


发表于 2018-11-06 12:22:58 回复(0)
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
/*
 大体思路是高斯消元法,数学背景就是XOR运算刚好是GF(2)上的加法,而所有的unsigned int刚好构成了GF(2)上32位的向量空间(本题只需30位)。
 我们要求的值,也就是颜色向量组的秩。求秩的一个基本思路是高斯消元法化成行标准形矩阵。由于GF(2)是一个域,矩阵也是定义在域上的矩阵,可以加减乘除。
 findFirstOne找到该数中非0的最高位,eg:findFirstOne(3)=2,findFirstOne(6)=3 findFirstOne(7)=3,仔细想想这就有点像线性代数里面找每行的第一个非0元。
 getMax很好看懂,如果a>=b,显然findFirstOne(a)>=findFirstOne(b),如果a>b,findFirstOne(a)也是大于等于findFirstOne(b),未必严格大于。
 我们先找第一个findFirstOne()最大的数,将它调到第一行,用异或操作消去该列的第一个非零元,然后指针指向第二个数,找第二个数到最后一个数中findFirstOne()
 最大的数,将它调到第二行,以此类推。
 for examle,输入:
 3
 1 2 3
 算法先将3和1交换
 3 2 1
 3要和2异或,但不能和1异或(if(findFirstOne(arr[scan]) == firstone)这个判断),因为1的第二位本来就是0
 变成
 3 1 1
 然后把3固定下来,指针指向2,变成3 1 0
 我们发现秩为2,就是cur-1,这个很好理解。本代码所有变量均使用unsigned,数组从1开始。对了,对于例子中的输入对应的二进制矩阵Binary是
 0 1 1
 0 1 0
 0 0 1
 rank(Binary) = 2
*/
unsigned findFirstOne(unsigned color)
{
    //cout<<(mask>1000000000)<<endl;
    unsigned cnt = 30,mask=0x20000000;//这个数字刚好是一个30位的二进制数,比1000000000稍大一些。
    while(mask)
    {
        if((mask&color)>0)//需要注意位运算优先级
            return cnt;
        else
        {
            mask = mask>>1;
            cnt--;
        }
    }
    return 0;
}

unsigned getMax(unsigned arr[],unsigned start,unsigned length)
{
    /*
        arr:一个unsigned数组,从1开始
        start:开始扫描的位置
        length:这个数组的长度
        返回:这个数组元素最大值对应的下标
    */
    unsigned cnt;
    unsigned maxunsign = 0,argmax = start;
    for(cnt = start;cnt<=length;++cnt)
    {
        if(arr[cnt] > maxunsign)
        {
            maxunsign = arr[cnt];
            argmax = cnt;
        }
    }
    if(maxunsign == 0)//已经全0,行标准型已经完成
        return 0;
    else
        return argmax;
}

int main()
{
    unsigned n,cur=1,arr[MAX],input,scan;
    unsigned ret,firstone;
    scanf("%u",&n);getchar();//使用getchar吸收换行符
    input = n;
    while(input--)
        cin>>arr[n-input];//从1开始输入
    for(cur = 1;cur<=n;++cur)
    {
        //依次扫描各行
        ret = getMax(arr,cur,n);
        if(!ret)
            break;
        else if(ret!=cur)
            swap(arr[cur],arr[ret]);
        firstone = findFirstOne(arr[cur]);//反复用到,先记下来
        for(scan = cur+1;scan<=n;++scan)
        {
            //行标准型要求每行首个非零元所在的列除了这个非零元以外全为0
            if(findFirstOne(arr[scan]) == firstone)
                arr[scan] = arr[cur] ^ arr[scan];
        }
    }
    cout<<cur-1<<endl;
    return 0;
}

发表于 2018-02-24 00:53:43 回复(0)
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{     int n,a[51];     cin>>n;     for(int i=0;i<n;i++)         cin>>a[i];     for(int i=n-1;i>0;i--)     {         sort(a,a+i+1);         for(int j=i-1;j>=0;j--)         {             if((a[j]^a[i]) < a[j])                 a[j] ^= a[i];         }     }     int k;     for(k=0;a[k]==0;k++);     cout<<n-k<<endl;     return 0;
}

发表于 2018-01-24 23:37:25 回复(0)
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[50][32],equ,var=32;
int solve(){
    int res=0,c,j,i,k;
    for(c=0;c<var&&res<equ;c++,res++){
        for(i=res;i<equ;i++)
            if(a[i][c]) break;
        if(equ==i) res--;
        else{
            for(k=0;k<var;k++) swap(a[res][k],a[i][k]);
            for(k=i+1;k<equ;k++)
                if(a[k][c])
                    for(j=c;j<var;j++)
                        a[k][j]^=a[res][j];
        }
    }
    return res;
} 
int main(){
    int i,tmp;
    for(scanf("%d",&equ),i=0;i<equ;i++){
        scanf("%d",&tmp);
        int index=31;
        while(tmp)
            a[i][index--]=tmp%2,tmp/=2;
    }
    printf("%d\n",solve());
}//求出矩阵的秩就可以了

发表于 2017-10-20 19:03:21 回复(0)
// 从大到小遍历数组,当前元素与仅次于当前元素大小的元素如果长度相同, 异或之后消除第二个元素的最高位上的1,并把异或的结果复制给第二个元素,
每一个有1的位只留一个元素就够了。最后不是0的元素就是需要的原料。

var n = parseInt(readline().trim());
var arr = readline().trim().split(' ').map(function(item) {
    return parseInt(item);
});
for (var i = 0; i < arr.length; i ++) {
    arr.sort(function(item1, item2) {
        return item2 - item1;
    });
    for (var j = i + 1; j < arr.length; ++ j) {
        if ((arr[i] ^ arr[j]) < arr[j]) {
            arr[j] ^= arr[i];
        }
    }
}
var result = 0;
for (i = 0; i < n; i ++) {
    if (arr[i] !== 0) {
        result ++;
    }
}
console.log(result);
发表于 2017-09-12 14:24:56 回复(0)
高斯消元的代码 复杂度 O(n^2*logn)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <set>
#include <cmath>
#include <map>

using namespace std;


int high_bit(int x)
{
int bit = 0;
while(x)
{
x >>= 1;
++ bit;
}
return bit;
}

int main(int argc, char const *argv[])
{
int n;
int ary[55];
while(~scanf("%d",&n))
{
for(int i = 0; i < n ; ++ i)
{
scanf("%d",ary+i);
}

int ans = 0;

sort(ary,ary+n);

int i;
for(i = n - 1; i >= 0 ; --i)
{
if(!ary[i])
break;
int bit = high_bit(ary[i]);
for(int j = i - 1 ; j >= 0 ; -- j)
{
if(bit == high_bit(ary[j]))
ary[j] ^= ary[i];
}
sort(ary,ary+i);
}

printf("%d\n",n-i-1);
}
return 0;
}
编辑于 2017-02-02 23:09:59 回复(0)
/**  * Created by hudaoyun on 16/8/24.
 *参考一楼的答案,求矩阵的秩  */ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Scanner; public class Main { public static void main(String[] args){
        Scanner in = new Scanner(System.in); int n = in.nextInt();
        ArrayList<Integer> colors = new ArrayList<Integer>(); for (int i = 0; i < n; i++){ int x = in.nextInt(); colors.add(x);
        }
        Collections.sort(colors); int bigest = n-1; int bigsecond = bigest - 1; int result = 0; while(colors.size() > 2){ if (getHighPosition(colors.get(bigest)) == getHighPosition(colors.get(bigsecond))){ int temp = colors.get(bigest) ^ colors.get(bigsecond); if (!colors.contains(temp)){ colors.add(temp);
                    Collections.sort(colors);
                    bigest = colors.size() - 1;
                    bigsecond = bigest - 1;
                }
            }else{
                result++;
            } colors.remove(colors.size() - 1);
            bigest = bigsecond;
            bigsecond--;
        }
        System.out.println(result + 2);

    } public static int getHighPosition(int a){ int count = 0; while(a > 0){
            count++;
            a = a >> 1;
        } return count;
    }
}


发表于 2016-08-25 15:34:40 回复(0)
/*参考loolroco写出来的代码*/

#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<math.h>
#include<algorithm>
using namespace std;

int highPostion(int a){
	int res = 0;
	while (a){
		a >>= 1;
		res++;
	}
	return res;
}

int main(){
	int n;
	while (cin >> n){
		int res = 0;
		set<int> s;
		for (int i = 0; i<n; i++){
			int tmp; cin >> tmp;
			s.insert(tmp);
		}
		set<int>::reverse_iterator r = ++s.rbegin();
		int esVal, endVal;
		while (s.size()>2){
			esVal = *r--;
			endVal = *r;
			while (highPostion(endVal) == highPostion(esVal) && s.size() >= 2){
				int tmp = esVal ^ endVal;
				if (s.find(tmp) == s.end()){
					s.insert(tmp);
				}
				s.erase(endVal);
				r = ++s.rbegin();
				esVal = *r--;
				endVal = *r;
			}
			res++;
			s.erase(endVal);
			r = ++s.rbegin();
		}
		cout << res + s.size() << endl;
	}
	return 0;
}

发表于 2016-08-12 17:14:17 回复(0)
按照 Debug_Li 说的高斯消除的思路写的程序。 O(n)时间复杂度。
#include <iostream>
#include <vector>

using namespace std;

int main(){
  int cnt = 29;
  cin >> cnt;
  vector<int> nums(cnt);
  for(int i=0; i<cnt; ++i){
  	cin >> nums[i];
  }

  vector<bool> mask(cnt, false);
  int mask_bits = 0x01;
  for(int i=0; i<32; ++i){
  	int cur = 0;
  	for(cur=0; cur<cnt; ++cur){
  	  // find one number as base
  	  if(mask[cur] == false && ((nums[cur]&mask_bits) > 0) )
  	  {
		mask[cur] = true;
		break;
	  }
  	}
  	// then xor the found base to all other nonmask number
  	for(int j=cur+1; j<cnt; ++j){
  	  if( (nums[j]&mask_bits) > 0 ){
  	  	nums[j] ^= nums[cur];
  	  }
  	}
  	mask_bits = mask_bits << 1;
  }
  
  // count the base number
  cnt = 0;
  for( int i=0; i<nums.size(); ++i){
  	if(mask[i] == true){
  	  ++cnt;
  	}
  } 
  cout << cnt << endl;
  return 0;
}

编辑于 2016-08-09 00:15:50 回复(1)
程序搬运工
import java.util.*;
public class Main{
    public static void  main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int[] arr=new int[n];
        for(int i=0;i<n;i++){
            arr[i]=sc.nextInt();
        }
        for(int i=n-1;i>0;--i){
            Arrays.sort(arr,0,i+1);
            for(int j=i-1;j>=0;--j){
                if((arr[i]^arr[j])<arr[j]){
                    arr[j]^=arr[i];
                }
            }
        }
        int count=0;
        for(count=0;arr[count]==0;++count);
        System.out.println(n-count);
    }
}

发表于 2018-07-24 15:33:08 回复(0)
看了大家写的,思路都差不多,就是写法不一样,附上我的代码:
#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    int i,j,n,x[55];
    cin>>n;
    for(i=0;i<n;++i)
        cin>>x[i];
    for(i=n-1;i>0;--i)
    {
        sort(x,x+i+1);
        for(j=i-1;j>=0;--j)
            if((x[i]^x[j])<x[j])
                x[j]^=x[i];
    }
    for(i=0;x[i]==0;++i);
    cout<<n-i;
    return 0;
}

发表于 2017-04-14 12:20:45 回复(16)
//数组从小到大排列,从最下面一行开始,每次消去最高位的1,比如A行的系数减去B行,直接A = A^B就行
import java.util.*;
public class hunheyanliao {
	
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		while(scan.hasNext()){
			int n = scan.nextInt();
			int[] col = new int[n];
			for(int i=0; i<n; i++){
				col[i] = scan.nextInt();		
			}
			Arrays.sort(col);
			int count = 0;
			for(int i=n-1; i>=0; i--){
				for(int j=i-1; j>=0; j--){
					if(highbit(col[i]) == highbit(col[j])){
						col[j] = col[j] ^ col[i];
					}
				}
				Arrays.sort(col);
			}
			for(int i=0 ;i<n;i++)
				if(col[i] !=0){
					count ++;
			}
			System.out.println(count);
		}
	}
	public static int highbit(int x){
		for(int i=31;i>=0;i--)
		{
		   int m = (x>>i)&1;
		   if(m != 0)
			   return i+1;
		}
		return 0;
	}
}


发表于 2016-08-23 11:14:02 回复(4)