生成排列和子集

本文介绍了生成排列的基本原理及实现方法,包括通过调整箭头方向来生成排列、利用逆序对生成排列以及格雷码的构造与翻转。同时简述了后续将涉及的子集生成方法。

生成排列和子集

这个只是单纯的总结,之后肯定还会搞的(如果没有退役的话)。


生成排列

不妨以生成 1∼n1 \sim n1n 的排列进行举例子,我们对于每一个数字的上面先定一个箭头,表示其可以向那边走。

一个数字移动的条件是其箭头指向的相邻的数组比其要小。

例如 1←2←\overset{\leftarrow}{1}\overset{\leftarrow}{2}12 这个时候 222 就是可以向左走一个位置的,也就是意味着下一个排列是 2←1←\overset{\leftarrow}{2}\overset{\leftarrow}{1}21

我们构造一个排列是从 1←2←…n←\overset{\leftarrow}{1}\overset{\leftarrow}{2} \dots \overset{\leftarrow}{n}12n 开始的。

  • 每次找到最大的可以移动的数。
  • 交换其和其箭头指向的数字。
  • 交换所有 i,i>mi, i > mi,i>m 的箭头的方向。

逆序对生成排列

对于一个数组 bbbbib_ibi 表示第 iii 个位置的逆序对数量。

我们从左到右进行考虑。

首先写出 nnn,先钦定其为第一个数字。

之后对于下一位如果 b2=0b_2 = 0b2=0 那么就是放在 nnn 的左边,不然是右边。

对于第 kkk 位来说其放置的位置就是原来数列的第 bkb_kbk 个位置。

显然这种构造是一个唯一对应一个排列的。


Gray Code

我们发现直接使用二进制进行传输信息使用的空间大小是不确定的,比如说传输 7=(111)27 = (111)_27=(111)2 和传输 8=(1000)28 = (1000)_28=(1000)2

格雷码就是构造一种使得相邻数字的二进制编号 111 的个数只相差 111 的编码。而且其只会使用小于最大编号的二进制位,这样的编码就是唯一的。

如何构造?

对于第 nnn 位可以直接由公式得到 g(n) = n ^ (n >> 1)

或者我们考虑从小到大进行构造,也就是对于 2n−12^{n - 1}2n1 的格雷码,我们现在前面全部放 000 之后再在前面放 111 两段一起拼起来。

0
1

00
01
10
11

000
001
010
011
100
101
110
111
如何翻转格雷码?
int rev_g(int g) {
    int res(0);
    for(; g; g >>= 1) res ^= g;
    return res;
}

后面的生成子集就先鸽一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值