组合数的输出
https://www.luogu.com.cn/problem/P1157
以$n=5$为例,那么原集合就是{$1,2,3,4,5$}
按照每个数字是否存在于子集合中可能有:
{$0,0,0,0,0$} ---->{}
{$0,0,0,0,1$} ---->{$5$}
{$0,0,0,1,0$} ---->{$4$}
{$0,0,0,1,1$} ---->{$4,5$}
{$0,0,1,0,0$} ---->{$3$}
…
这样的二进制形式,就可以模拟出所有的子集选择情况。
这些二进制,还是可以从0,一直到 31的, 也就是说,我们可以用循环从0遍历到31,就成功模拟了这32种情况,对应着32种子集合。假设我们写出了如下的代码:
for(int i=0;i<31;i++){
...
}
由于数字是从$0$到$31$,所以第一个考查的是0
,第二个考查的是1
,最后一个考查的是31
,对应二进制就是:
数字 | 对应的二进制 | 对应的集合 |
---|---|---|
$0$ | 0 0 0 0 0 |
{} 空集合 |
$1$ | 0 0 0 0 1 |
{5} |
$2$ | 0 0 0 1 0 |
{4} |
$3$ | 0 0 0 1 1 |
{4,5} |
$4$ | 0 0 1 0 0 |
{3} |
$5$ | 0 0 1 0 1 |
{3,5} |
$6$ | 0 0 1 1 0 |
{3,4} |
$7$ | 0 0 1 1 1 |
{3,4,5} |
$8$ | 0 1 0 0 0 |
{2} |
$9$ | 0 1 0 0 1 |
{2,5} |
$10$ | 0 1 0 1 0 |
{2,4} |
$11$ | 0 1 0 1 1 |
{2,4,5} |
$12$ | 0 1 1 0 0 |
{2,3} |
$13$ | 0 1 1 0 1 |
{2,3,5} |
$14$ | 0 1 1 1 0 |
{2,3,4} |
$15$ | 0 1 1 1 1 |
{2,3,4,5} |
$16$ | 1 0 0 0 0 |
{1} |
$17$ | 1 0 0 0 1 |
{1,5} |
$18$ | 1 0 0 1 0 |
{1,4} |
$19$ | 1 0 0 1 1 |
{1,4,5} |
$20$ | 1 0 1 0 0 |
{1,3} |
$21$ | 1 0 1 0 1 |
{1,3,5} |
$22$ | 1 0 1 1 0 |
{1,3,4} |
$23$ | 1 0 1 1 1 |
{1,3,4,5} |
$24$ | 1 1 0 0 0 |
{1,2} |
$25$ | 1 1 0 0 1 |
{1,2,5} |
$26$ | 1 1 0 1 0 |
{1,2,4} |
$27$ | 1 1 0 1 1 |
{1,2,4,5} |
$28$ | 1 1 1 0 0 |
{1,2,3} |
$29$ | 1 1 1 0 1 |
{1,2,3,5} |
$30$ | 1 1 1 1 0 |
{1,2,3,4} |
$31$ | 1 1 1 1 1 |
{1,2,3,4,5} |
由于例子是$r=3$,所以:
数字 | 对应的二进制 | 对应的集合 |
---|---|---|
$7$ | 0 0 1 1 1 |
{3,4,5} |
$11$ | 0 1 0 1 1 |
{2,4,5} |
$13$ | 0 1 1 0 1 |
{2,3,5} |
$14$ | 0 1 1 1 0 |
{2,3,4} |
$19$ | 1 0 0 1 1 |
{1,4,5} |
$21$ | 1 0 1 0 1 |
{1,3,5} |
$22$ | 1 0 1 1 0 |
{1,3,4} |
$25$ | 1 1 0 0 1 |
{1,2,5} |
$26$ | 1 1 0 1 0 |
{1,2,4} |
$28$ | 1 1 1 0 0 |
{1,2,3} |
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int a[N];
int main() {
int n, r;
cin >> n >> r;
//如果是正序
for (int S = 0; S <= (1 << n) - 1; S++) {
//每次循环需要清0
memset(a, 0, sizeof a);
int cnt = 0;
for (int i = n - 1; i >= 0; i--) //遍历S的每一个二进制位(从高位到低位)
if (S & (1 << i)) a[cnt++] = i; //记录S的哪些数位不为0
//只需要r位
if (r == cnt) {
cout << S << " {";
/*
数组内容4,对应着数字1
数组内容3,对应着数字2
数组内容2,对应着数字3
数组内容1,对应着数字4
数组内容0,对应着数字5
就是一个两者相加等于n的关系。
*/
for (int i = 0; i < cnt; i++) cout << n - a[i] << " ";
cout << "}\n";
}
}
return 0;
}
大数在前,才能保证 10110 早于 10101.修改一下:
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int a[N];
int main() {
int n, r;
cin >> n >> r;
//大数在前,才能保证 10110 早于 10101
for (int S = (1 << n) - 1; S >= 0; S--) {
//每次循环需要清0
memset(a, 0, sizeof a);
int cnt = 0;
for (int i = n - 1; i >= 0; i--) //遍历S的每一个二进制位(从高位到低位)
if (S & (1 << i)) a[cnt++] = i; //记录S的哪些数位不为0
//只需要r位
if (r == cnt) {
printf("%3d", S);
cout << " { ";
/*
数组内容4,对应着数字1
数组内容3,对应着数字2
数组内容2,对应着数字3
数组内容1,对应着数字4
数组内容0,对应着数字5
就是一个两者相加等于n的关系。
*/
for (int i = 0; i < cnt; i++) cout << n - a[i] << " ";
cout << "}\n";
}
}
return 0;
}