USACO 2.1 海明码 Hamming Codes
题目
题目描述
给出 N,B 和 D,要求找出 N 个由0或1组成的编码(1 <= N <= 64),每个编码有 B 位(1 <= B <= 8),使得两两编码之间至少有 D 个单位的“Hamming距离”(1 <= D <= 7)。“Hamming距离”是指对于两个编码,他们二进制表示法中的不同二进制位的数目。看下面的两个编码 0x554 和 0x234(0x554和0x234分别表示两个十六进制数)
0x554 = 0101 0101 0100
0x234 = 0010 0011 0100
不同位 xxx xx
因为有五个位不同,所以“Hamming距离”是 5。
输入输出格式
输入格式:
一行,包括 N, B, D。
输出格式:
N 个编码(用十进制表示),要排序,十个一行。如果有多解,你的程序要输出这样的解:假如把它化为2^B进制数,它的值要最小。
输入输出样例
说明
请解释:“必须与其他所有的数相比,Hamming距离都符合要求,这个数才正确”
答:如样例输出,0和7,0和25,0和……比较都符合海明码,同样7和25,7和30,7和……比较也符合要求,以此类推。 就这样了。 题中至少有D个单位,意思就是大于等于D个单位的都可以。
USACO 2.1
翻译来自NOCOW
大意
找到按字母序排前n个的数,满足其二进制位数相差大于等于D
分析
这道题我们需要用到一点小技巧:
a xor b 得到相同为0,不同为1的数
解释一下k&(-k),结果就是去掉k右起第一个1的左边部分;
对于一个带符号整型,-k的结果就是把k的符号位取反后的补码;
举两个例子:当k=00010101时,-k=11101011;
k=00010101
-k=11101011
k&(-k)=00000001
当k=01001000时,-k=10110111;
k=01001000
-k=10111000
k&(-k)=00001000
也就是说k-=k&(-k)就可以做到,去掉k中最后一个1
那么这个代码就很好理解了 //c。。
然后暴力枚举就好了
代码
1 #include<iostream> 2 using namespace std; 3 int n,b,d,k,num; 4 bool ok; 5 int a[100]; 6 int check(int x,int y) 7 { 8 int k=x xor y,ans=0; 9 while (k>0) 10 { 11 ans++; 12 k-=k&(-k); 13 } 14 return ans; 15 } 16 int main () 17 { 18 cin>>n>>b>>d; 19 while(k<n) 20 { 21 ok=1; 22 for (int i=1;i<=k;i++) 23 if (check(a[i],num)<d) 24 { 25 ok=0; 26 break; 27 } 28 if (ok==1) a[++k]=num; 29 num++; 30 } 31 while (k--){ 32 cout<<a[n-k]<<" "; 33 if ((n-k)%10==0) cout<<endl; 34 } 35 }