废话不多说上链接:https://www.luogu.com.cn/problem/P1157
题干:
对于这道题,我们可以发现,取r个元素,必定是n个元素的子集,
所以我们只需要求出遍历所有子集,然后将子集内有r个元素的子集记下,按字典序从小到大输出就可。
1.建立全集(不知道怎么操作的看我上一篇文章)做洛谷p1036 选数 ,对子集枚举,二进制的感想-CSDN博客
int u = (1 << n)-1;
2.遍历子集
for (int s = u; s >=0; s--)
3.找到内部元素为r的子集:__builtin_popcount()
说一下为什么要从u开始,逐渐减小到0;
假设s从0开始增大,并且00001对应的是1,那么s最先枚举到的是
U: 5 4 3 2 1
S: 0 0 1 1 1 ——1 2 3
next
S: 0 1 0 1 1 —— 1 2 4
next
S: 0 1 1 0 1—— 1 3 4
很明显中间缺少了1 2 5.
但是如果我们将子集从U开始枚举,并且00001对应的是5,那么每次减少1会变成:
U: 1 2 3 4 5
S: 1 1 1 0 0——123
next
S: 1 1 0 1 0——124
S: 1 1 0 0 1——125
完整代码:
int main()
{
int n, r;
cin >> n >> r;
int t = 1;
for (int i = n; i >= 1; i--)flag[t++] = i;
int u = (1 << n)-1;
for (int s = u; s >=0; s--)
{
if (__builtin_popcount(s) == r)
{
for (int i = n; i>=1; i--)
{
if (s & (1 << (i - 1)))cout << setw(3) << flag[i];
}
cout << endl;
}
}
}