关于二进制匹配的方法:异或

二进制实例

蓝桥杯:试题 算法训练 审美课

异或常用于只有01的数组进行取反,并且需要转成10进制的题型。

二进制异或

假设有一个2位的二进制数,该二进制数(如10)异或满位(如11)之后,异或是同真异假,所以10异或11会等于01即1。

异或实例用法

如实例审美课

输入格式
第一行两个数n和m,表示学生数和图画数;
  接下来是一个n*m的01矩阵A:
  如果aij=0,表示学生i觉得第j幅画是小朋友画的;
  如果aij=1,表示学生i觉得第j幅画是梵高画的。

输出格式
  输出一个数ans:表示有多少对同学的答案完全相反。
样例输入
3 2
1 0
0 1
1 0

样例输出
2

样例说明
  同学1和同学2的答案完全相反;
  同学2和同学3的答案完全相反;
  所以答案是2。

  1. 由于要求完全相反的同学,然后是01矩阵A,如果后面计算直接遍历的话,要用两层循环。所以用一个arr数组保存每一行的10进制数,sum数组用来保存每一行数据的出现次数,用来一个max来保存m位的最大值。

  2. 然后接受过程用tmp保存当前行当前列,并保存进arr[i];arr[i]出现一次,对应sum++。

  3. 最后遍历每一行的完全相反数的个数(arr[i]异或max),由于匹配会重复,所以结果/2。

import java.util.Scanner;

public class Main{
	static int[] arr = new int[50005];//因为如题有n行,n <= 50000 
	static int[] sum = new int[1050000];//因为20位化成10进制为1048575
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(), m = sc.nextInt();
		
		int tmp = 0, max = (1 << m) - 1;
		
		for(int i = 0;i < n;++i){
			for(int j = 0;j < m; ++j){
				tmp = sc.nextInt();
				arr[i] = (arr[i] << 1) + tmp;//二进制保存
			}
			sum[arr[i]]++;
		}
		
		//多少对答案完全相反
		int ans = 0;
		
		for(int i = 0;i < n; ++i){
			ans += sum[arr[i] ^ max];
		}
		
		System.out.println(ans / 2);
	}

}

改进

  • 该部分代码借鉴于csdn,但是c++给数组分配内存占用很少空间,相反Java很占用内存。

  • 所以动态分配很重要,static不会回收内存,改成局部变量,数组太占内存,改成map动态分配。最后内存依然有160多MB,而c++只有6MB左右,对比一下,c++的动态分配内存是比较奈斯的。

故将原题的arr数组改成局部变量,sum数组太大了,用HashMap比较合适,改动如下:

int[] arr = new int[50005];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();

map.put(arr[i], map.getOrDefault(arr[i], 0) + 1);

if(map.containsKey(arr[i] ^ max)){
      ans += map.get(arr[i] ^ max);
}
posted @ 2020-12-31 23:16  acchris  阅读(748)  评论(0)    收藏  举报