标签:Gosper 组合 串串 int 生成 算法 Hack lb
XIN 队算法之枚举组合 .
枚举组合的一个非递归做法叫 Gosper's Hack 算法,思路就是对每个组合,用 01 串表示其选或不选,这样必然可以表示所有组合 .
我们考虑如何生成一个组合的下一个组合,因为是组合,所以我们要保证串串的 popcount 不变,这样就考虑把最后一个 01 变成 10,这样显然是对的 .
而且要保证生成完的串串 \(b'\) 和原来的串串 \(b\) 的差值 \(b'-b\) 最小,这样我们才能保证生成所有组合,于是我们只需要把所有 1 集中到最右边即可 .
我们考虑如何用位运算描述这个过程,具体可以看下面的代码手玩一下 .
比如按字典序生成 \(n\) 元集合所有 \(k\) 元子集就可以写为
const int N = 1 << 25;
int n, k, state[N], cc;
int main()
{
scanf("%d%d", &n, &k);
if (!k) return 0;
int cur = (1 << k) - 1, limit = (1 << n);
while (cur < limit)
{
state[++cc] = cur;
int lb = cur & -cur, r = cur + lb;
cur = ((r ^ cur) >> __builtin_ctz(lb) + 2) | r;
// 如果不用 builtin 函数可以写 cur = (((r ^ cur) >> 2) / lb) | r;
}
for (int i=cc; i>=1; i--, puts(""))
for (int j=n-1; j>=0; j--)
if (state[i] >> j & 1) printf("%d ", n-j);
return 0;
}
时间复杂度为 \(\displaystyle O\left(\dbinom nk\cdot n\right)\),非常的高效,也非常的简洁 .
标签:Gosper,组合,串串,int,生成,算法,Hack,lb 来源: https://www.cnblogs.com/CDOI-24374/p/16642647.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。