CSP初赛复习-30-格雷码
二进制编码
二进制和我们平时用的十进制,其实并没有什么本质区别,只是平时我们是“逢十进一”,这里变成了“逢二进一”而已
每一位,相比于十进制下的 0~9 这十个数字,我们只能用 0 和 1 这两个数字
任何一个十进制的整数,都能通过二进制表示出来。把一个二进制数,对应到十进制,非常简单,就是把从右到左的第 N 位,乘上一个 2 的 N 次方,
然后加起来,就变成了一个十进制数
例如
1101
1*2^3+1*2^2+0*2^1+1*2^0=8+4+1=13
格雷码
格雷码(Gray code),又称格雷数码或反射二进制码,是一种二进制编码方式
在格雷码中,相邻的两个数仅有一位二进制位不同,使得在数字之间的转换只需要进行一次位运算,避免了普通二进制码转换时可能需要多次位运算的情况
格雷码优点
任意两个相邻数字的码组(包括首尾码组),只有一位二进制不同。
因为它有这种特点,当数字递增或递减时,码组的变化,每次就只有一位二进制有变化。这就可以避免变化时间参差不齐而带来的干扰
格雷码缺点
就是不够直观,不能直接看出它所代表的数值
格雷码生成方法
格雷码的生成方法有多种,其中最常见的是递归法和镜像法。
递归法
递归法是通过对前n-1位二进制码进行递归生成,然后在最高位前加0或1来生成n位格雷码。
镜像法
镜像法则是通过镜像前n-1位二进制码,并在最高位前加0或1来生成n位格雷码
格雷码示例
2位二进制串
00 01 11 10
3位二进制串
000 001 011 010 110 111 101 100
4位二进制串
0000 0001 0011 0010 0110 0111 0101 0100 1100 1101 1111 1110 1010 1011 1001 1000
例题 格雷码 CSP-S2019
题目描述
通常,人们习惯将所有n位二进制串按照字典序排列,例如所有 2 位二进制串按字典序从小到大排列为:00,01,10,11
格雷码(Gray Code)是一种特殊的n位二进制串排列法,它要求相邻的两个二进制串间恰好有一位不同,特别地,第一个串与最后一个串也算作相邻
所有 2 位二进制串按格雷码排列的一个例子为:00,01,11,10
n 位格雷码不止一种,下面给出其中一种格雷码的生成算法
1 位格雷码由两个 1 位二进制串组成,顺序为:0,1
2 n+1 位格雷码
n+1 位格雷码的前2^n个二进制串,可以由依此算法生成的n位格雷码(总共2 ^n 个n位二进制串)按顺序排列,再在每个串前加一个前缀 0 构成
n+1 位格雷码的后2^n个二进制串,可以由依此算法生成的n位格雷码(总共2 ^n 个n位二进制串)按逆序排列,再在每个串前加一个前缀 1 构成
综上,n+1位格雷码,由n位格雷码的2 ^n个二进制串按顺序排列再加前缀 0,和按逆序排列再加前缀 1 构成,共2 ^(n+1)个二进制串。另外,对于n位格雷码中的 2 ^n个 二进制串,我们按上述算法得到的排列顺序将它们从 0∼ 2 ^n-1编号
按该算法,2 位格雷码可以这样推出:
已知 1 位格雷码为 0,1。
前两个格雷码为 00,01。后两个格雷码为 11,10。合并得到 00,01,11,10,编号依次为 0 ~ 3
同理,3 位格雷码可以这样推出
已知 2 位格雷码为:00,01,11,10。
前四个格雷码为:000,001,011,010。后四个格雷码为:110,111,101,100。
合并得到:000,001,011,010,110,111,101,100,编号依次为 0 ~ 7
现在给出n,k请你求出按上述算法生成的n位格雷码中的k号二进制串
输入格式
仅一行两个整数n,k,意义见题目描述
输出格式
仅一行一个n位二进制串表示答案
样例输入1
2 3
样例输出1
10
样例输入2
3 5
样例输出2
111
样例输入2
44 1145141919810
样例输出2
00011000111111010000001001001000000001100011
【数据范围】
对于 50% 的数据:n≤10
对于 80%的数据:k≤5×10^6
对于 95% 的数据:k≤2^(63−1)
对于 100% 的数据:1≤n≤64, 0≤k<2^n
大致思路
1 递归法求格雷码 求n位格雷码的第k位,可以分2部分求解,前半部分后后半部分
2 前半部分为 0和f(n-1,k) 两部分组成
1位格雷码
0 1
2位格雷码
00 01 11 10
前半部分0+第k位
4 后半部分为 0和f(n-1,(x<<1)-k-1) 两部分组成
1位格雷码
0 1
2位格雷码
00 01 11 10
后半部分1+第k位(由于后半部分是逆序,因此需要转换)
2位格雷码总共有4个数字,总共有2^n --2^2=4
后半部分逆序,对应下标第3位 2^2-1-0=3,第4位2^2-1=2 (下标从0开始)
因此后半部分下标位2^n-1-k
由于前面算出x=2^(n-1)
所以2^n=x * 2 = (x<<1)
所以2^n-1-k=(x<<1)-1-k
参考程序
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;//unsigned long long 别名ULL
int n;//n位格雷码
ULL k;//第k位
/*
n位 格雷码的第k位
*/
void f(int n,ULL k){
if(n==1){//递归出口 1位格雷码
if(k) cout<<"1";//第1位是1
else cout<<"0";//第0位是0
return;
}
ULL x =(1ull<<n-1);//1左移n-1位 2^(n-1)
if (k<x){//左半部分
cout<<"0";//前面加0
f(n-1,k);//n-1位原样输出
}else{//右半部分
cout<<"1";//前面加1
/*
从后前前逆序 右半部分 最大2^n
位置对应 0 -- 2^(n)-1 又 k=2^(n-1) 所以0--k<<1-1
位置对应 1 -- 2^(n)-2 又 k=2^(n-1) 所以0--k<<1-2
位置对应 k -- 2^(n)-k 又 k=2^(n-1) 所以0--k<<1-k
*/
f(n-1,(x<<1)-k-1);
}
}
int main(){
cin>>n>>k;//n位格雷码 第k位
f(n,k);//求n位格雷码 第k位
return 0;
}
作者:newcode 更多资源请关注纽扣编程微信公众号

从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习

浙公网安备 33010602011771号