组合数的输出
以(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 << "}
";
}
}
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 << "}
";
}
}
return 0;
}