直接枚举,然后用位运算计算二进制表示时1的个数。代码:
/* ID: xincaor1 LANG: JAVA TASK: hamming */ import java.util.*; import java.math.*; import java.io.*; public class hamming { public static boolean check(int a,int b,int d) { int x; x= a^b; x= (x&0x55555555) + ((x >> 1)&0x55555555); x= (x&0x33333333) + ((x >> 2)&0x33333333); x= (x&0x0F0F0F0F) + ((x >> 4)&0x0F0F0F0F); x= (x&0x00FF00FF) + ((x >> 8)&0x00FF00FF); x= (x&0x0000FFFF) + ((x >> 16)&0x0000FFFF); if (x >= d) return true; else return false; } public static void main (String[] args) throws IOException{ int[] ans = new int[200]; int n,b,d,k; Scanner cin = new Scanner(new FileReader("hamming.in")); PrintWriter out = new PrintWriter(new BufferedWriter( new FileWriter("hamming.out"))); n=cin.nextInt(); b=cin.nextInt(); d=cin.nextInt(); k=0; for(int i=0;i<(int)Math.pow(2.0,b*1.0);i++) { int j; for(j=0;j<k;j++) { if(check(ans[j],i,d)==false) break; } if(j==k) ans[k++]=i; if(k==n) break; } //System.out.print(ans[0]); out.print(ans[0]); for(int i=1;i<k;i++) { if(i%10==0) { //System.out.println(); //System.out.print(ans[i]); out.println(); out.print(ans[i]); } else { //System.out.print(" "+ans[i]); out.print(" "+ans[i]); } } out.println(); cin.close(); out.close(); } }
matrix67有关位运算的讲解实在是太好了,终于派上用场了,现在摘取一些,方便以后查阅。
Pascal和C中的位运算符号
下面的a和b都是整数类型,则:
C语言 | Pascal语言
-------+-------------
a & b | a and b
a | b | a or b
a ^ b | a xor b
~a | not a
a << b | a shl b
a >> b | a shr b
一个看起来非常诡异的swap过程:procedure swap(var a,b:longint);
begin
a:=a xor b;
b:=a xor b;
a:=a xor b;
end;
一些常见的二进制位的变换操作。
功能 | 示例 | 位运算
----------------------+---------------------------+--------------------
去掉最后一位 | (101101->10110) | x shr 1
在最后加一个0 | (101101->1011010) | x shl 1
在最后加一个1 | (101101->1011011) | x shl 1+1
把最后一位变成1 | (101100->101101) | x or 1
把最后一位变成0 | (101101->101100) | x or 1-1
最后一位取反 | (101101->101100) | x xor 1
把右数第k位变成1 | (101001->101101,k=3) | x or (1 shl (k-1))
把右数第k位变成0 | (101101->101001,k=3) | x and not (1 shl (k-1))
右数第k位取反 | (101001->101101,k=3) | x xor (1 shl (k-1))
取末三位 | (1101101->101) | x and 7
取末k位 | (1101101->1101,k=5) | x and (1 shl k-1)
取右数第k位 | (1101101->1,k=4) | x shr (k-1) and 1
把末k位变成1 | (101001->101111,k=4) | x or (1 shl k-1)
末k位取反 | (101001->100110,k=4) | x xor (1 shl k-1)
把右边连续的1变成0 | (100101111->100100000) | x and (x+1)
把右起第一个0变成1 | (100101111->100111111) | x or (x+1)
把右边连续的0变成1 | (11011000->11011111) | x or (x-1)
取右边连续的1 | (100101111->1111) | (x xor (x+1)) shr 1
去掉右起第一个1的左边 | (100101000->1000) | x and (x xor (x-1))
二进制中的1有奇数个还是偶数个var
x:longint;
begin
readln(x);
x:=x xor (x shr 1);
x:=x xor (x shr 2);
x:=x xor (x shr 4);
x:=x xor (x shr 8);
x:=x xor (x shr 16);
writeln(x and 1);
end.
计算二进制中的1的个数
x := (x and $55555555) + ((x shr 1) and $55555555);
x := (x and $33333333) + ((x shr 2) and $33333333);
x := (x and $0F0F0F0F) + ((x shr 4) and $0F0F0F0F);
x := (x and $00FF00FF) + ((x shr 8) and $00FF00FF);
x := (x and $0000FFFF) + ((x shr 16) and $0000FFFF);
二分查找32位整数的前导0个数
int nlz(unsigned x)
{
int n;
if (x == 0) return(32);
n = 1;
if ((x >> 16) == 0) {n = n +16; x = x <<16;}
if ((x >> 24) == 0) {n = n + 8; x = x << 8;}
if ((x >> 28) == 0) {n = n + 4; x = x << 4;}
if ((x >> 30) == 0) {n = n + 2; x = x << 2;}
n = n - (x >> 31);
return n;
}