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++){
    ...
}

由于数字是从031,所以第一个考查的是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;
}
posted @   糖豆爸爸  阅读(126)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2019-07-13 mount.cifs Windows共享目录权限755问题
2018-07-13 挑战扫雷世界纪录
2018-07-13 centos java tomcat 中文乱码解决办法
2017-07-13 杀掉TOMCAT并重启的脚本
2016-07-13 读取EXCEL的办法
2016-07-13 考勤打卡设计方案
2015-07-13 融云的技术资料
Live2D
点击右上角即可分享
微信分享提示