LOADING

加载过慢请开启缓存 浏览器默认开启

c++-格雷码

2024/9/10

oi wiki原文:链接

洛谷例题:链接

引入

格雷码定义

构造格雷码

我们先来讲一下构造的方法再讲为什么吧。不然除非你拥有发明这种算法的实力。。
大佬当我什么都没说(好像大佬也刷不到这个蒟蒻的blog

手动构造

k 位的格雷码可以通过以下方法构造。我们从全 0 格雷码开始,按照下面策略:
翻转最低位得到下一个格雷码,(例如 000\to 001);
把最右边的 1 的左边的位翻转得到下一个格雷码,(例如 001\to 011);

交替按照上述策略生成 2^{k-1} 次,可得到 k 位的格雷码序列。

为什么这么做呢?就相当于十进制1 ~ 2^k, 把每一位转化成对应格雷码就是这样了。
那为什么十进制这么转化成格雷码?请看下文正确性证明。

镜像构造

镜像构造格雷码

这个方法是我最推荐的,最为简单的。

他原文是这样的:“k 位的格雷码可以从 k-1 位的格雷码以上下镜射后加上新位的方式快速得到”

人话来说,就例如图片里k = 2编程k = 3,就把k = 2的格雷码先照搬过来,再把它反着写一遍跟在原来的后面,最后原来的前面加个零0后面的加一个1,就变成k = 3的格雷码了。

原理:蒟蒻也不知道诶,可能就是单纯的找规律吧~(试图萌混过关

格雷码转二进制

计算方法

格雷码表

看不懂?很正常。因为我也看不懂。。。太抽象了。

直接看代码也许还会好理解一点怎么做:

int g(int n) { return n ^ (n >> 1); }

代码很简单吧?假设二进制1011要转换成对应格雷码,就右移一位(除以2)并与其异或。
大概是这样的:

1011 -> 101
101 ^ 1011 = 1110

正确性证明

关于这个我专门录了一期视频,个人感觉还是讲的挺详细的,可能有的时候结巴了一点(对不起

讲解视频

然后OI WIKI上的解释是这样的:

OI WIKI证明

很抽象,建议看我视频然后点赞的说(企图萌混过关

例题

洛谷例题

#include <bits/stdc++.h>
using namespace std;

unsigned long long n = 5, k;
int main() {
    cin >> n >> k;
    k ^= k >> 1;
    for (int i = n - 1; i >= 0; i--) {
        cout << (k>>i&1);
    }

    return 0;
}

当然题解第一篇是最优解,但我觉得这样好理解一些。

首先,输入n,k,再讲十进制k转换为对应的格雷码

然后,从n-1位到第0为遍历输出

最后就没有啦,很简单把.^.

如果有不理解的地方那应该只能是k转换为格雷码,那么建议看一下我的15min视频.^.

再见啦~本文用一个星期零零散散地写完,希望大家喜欢