子集生成算法:给定一个集合,枚举所有可能的子集

给定一个集合,枚举所有可能的子集。

(为简单起见,本文讨论的集合中没有重复元素)

1、方法一:增量构造法

第一种思路是一次选出一个元素放到集合中,程序如下:

void print_subset(int n, int *A, int cur) {for (int i = 0; i < cur; i++) printf("%d ", A[i]);printf("\n");int s = cur ? A[cur - 1] + 1 : 0; //确定当前元素的最小可能值for (int i = s; i < n; i++) {A[cur] = i;print_subset(n, A, cur + 1); //递归构造子集}
}

由于 A 中的元素个数不确定,每次递归调用都要输出当前集合。另外,递归边界也不需要显式确定——如果无法继续添加元素,自然就不会再递归了。

该代码用到了定序的技巧:规定集合 A 中所有元素的编号从小到大排列,就不会把集合 {1, 2} 按照 {1, 2} 和 {2, 1} 输出两次了。

提示:在枚举子集的增量法中,需要使用定序的技巧,避免同一个集合枚举两次。

这棵解答树上有 1024 个节点:每个可能的 A 都对应一个结点,而 n n n 元素集合恰好有 2 n 2 ^n 2n 个子集,210 = 1024。

代码

// {0~n-1}的所有子集:增量构造法
#include<cstdio>
using namespace std;void print_subset(int n, int* A, int cur) {for(int i = 0; i < cur; i++) printf("%d ", A[i]); // 打印当前集合    printf("\n");int s = cur ? A[cur-1]+1 : 0; // 确定当前元素的最小可能值for(int i = s; i < n; i++) {A[cur] = i;print_subset(n, A, cur+1); // 递归构造子集}
}int A[10];
int main() {int n;scanf("%d", &n);print_subset(n, A, 0);return 0;
}

2、方法二:位向量法

第二种思路是构造一个位向量 B[i],而不是直接构造子集 A 本身,其中 B[i] = 1,当且仅当 i 在子集 A 中。递归实现如下:

void print_subset(int n, int *B, int cur) {if (cur == n) {for (int i = 0; i < cur; i++) {if (B[i]) printf("%d ", i); //打印当前集合}printf("\n");return ;}B[cur] = 1; //选第cur个元素print_subset(n, B, cur + 1);B[cur] = 0; //不选第cur个元素print_subset(n, B, cur + 1);
}

必须当 “所有元素是否选择” 全部确定完毕后才是一个完整的子集,因此当 if (cur == n) 成立时才输出。

现在的解答树上有 2047 个结点,比刚才的方法略多,因为所有部分解(不完整解)也对应着解答树上的结点。

提示:在枚举子集的位向量法中,解答树的节点数略多,但在多数情况下仍然够快。

这是一棵 n + 1 n+1 n+1 层的二叉树(cur 的范围0 ~ n),第0层有1个结点,第1层有2个结点,第2层有4个结点,第3层有8个结点,…,第 i i i 层有 2 i 2^i 2i 个结点,总数为 1 + 2 + 4 + 8 + . . . + 2 n = 2 n + 1 − 1 1 + 2 + 4 + 8 + ... + 2^n = 2^{n+1} - 1 1+2+4+8+...+2n=2n+11,和实验结果一致。

下图为这棵解答树。
在这里插入图片描述

代码

// {0~n-1}的所有子集:位向量法
#include<cstdio>
using namespace std;void print_subset(int n, int* B, int cur) {if(cur == n) {for(int i = 0; i < cur; i++)if(B[i]) printf("%d ", i); // 打印当前集合printf("\n");return;}B[cur] = 1; // 选第cur个元素print_subset(n, B, cur+1);B[cur] = 0; // 不选第cur个元素print_subset(n, B, cur+1);
}int B[10];
int main() {int n;scanf("%d", &n);print_subset(5, B, 0);return 0;
}

3、方法三:二进制法

还可以用二进制来表示 {0,1, 2,…,n - 1} 的子集 S:从右往左第 i i i 位(各位从0开始编号)表示元素 i i i 是否在集合 S 中。下图展示了二进制 0100011000110111是如何表示集合{0,1,2,4,5,9,10,14} 的。

在这里插入图片描述

注意:为了处理方便,最右边的位总是对应元素0,而不是元素1。

提示:可以用二进制表示子集,其中从右往左第 i i i 位(从0开始编号)表示元素 i i i 是否在集合中(1表示“在”,0表示“不在”)。

表示出集合后,还要对集合进行操作。常见的集合运算都可以用位运算符简单实现。最常见的二元运算符是与(&)、或(|)、非(!),它们和对应的逻辑运算非常相似,如下表所示。

在这里插入图片描述
“异或(XOR)”运算符“^",其规则是 “如果 A 和 B 不相同,在 A ^ B = 1,否则为0”。异或运算最重要的性质就是“开关性”——异或两次以后相当于没有异或,即 A^B^B = A。另外,与、或和异或都满足交换律:A&B = B&AA|B = B|AA^B = B^A

与逻辑运算符不同的是,位运算符(bitwise operator)是逐位进行的——两个 32 位整数的"按位与" 相当于 32 对 0/1 值之间的运算。下表比欧式了二进制数10110(十进制22)和01100(十进制12)之间的按位与、按位或、按位异或的值,以及对应的集合运算的含义。

在这里插入图片描述

可见,A&B、A|B 和 A^B 分别对应集合的交、并和对称差。另外,空集为0,全集{0, 1, 2, …, n − 1 n-1 n1} 的二进制为 n n n 个 1,即十进制 2 n − 1 2^n - 1 2n1为了方便,往往在程序中把全集定义为 ALL_BITS = (1 << n) - 1,则 A 的补集就是ALL_BITS^A 当然,直接用整数减法ALL_BITS - A 也可以,但速度比位运算 “^” 慢。

提示:当用二进制表示子集时,位运算中的按位与、或、异或对应集合的交、并和对称差。

如此,就可以用下面的程序输出子集 S 对应的各个元素:

void  print_subset(int n, int s) { //打印 {0, 1, 2, ..., n-1} 的子集Sfor (int i = 0; i < n; i++) {if (s & (1 << i)) printf("%d ", i); //利用了C语言“非0值都为真”的规定}printf("\n");
}

而枚举子集和枚举整数一样简单:

for (int i = 0; i < (1 << n); i++) { //枚举各子集所对应的编码0, 1, 2, ..., 2^n - 1print_subset(n, i);
}

代码

// {0~n-1}的所有子集:二进制法
#include<cstdio>
using namespace std;void print_subset(int n, int s) {  // 打印{0, 1, 2, ..., n-1}的子集Sfor(int i = 0; i < n; i++)if(s&(1<<i)) printf("%d ", i); // 这里利用了C语言“非0值都为真”的规定printf("\n");
}int main() {int n;scanf("%d", &n);for(int i = 0; i < (1<<n); i++)  // 枚举各子集所对应的编码 0, 1, 2, ..., 2^n-1print_subset(n, i);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/120778.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

36基于matlab的对分解层数和惩罚因子进行优化

基于matlab的对分解层数和惩罚因子进行优化。蚁狮优化算法优化VMD,算术优化算法优化VMD&#xff0c;遗传优化算法优化VMD&#xff0c;灰狼优化算法优化VMD&#xff0c;海洋捕食者优化算法优化VMD&#xff0c;粒子群优化VMD&#xff0c;麻雀优化算法优化VMD&#xff0c;鲸鱼优化…

C语言 每日一题 PTA 10.27 day5

1.高速公路超速处罚 按照规定&#xff0c;在高速公路上行使的机动车&#xff0c;达到或超出本车道限速的10 % 则处200元罚款&#xff1b; 若达到或超出50 % &#xff0c;就要吊销驾驶证。请编写程序根据车速和限速自动判别对该机动车的处理。 输入格式 : 输入在一行中给出2个正…

win10 + VS2017 编译libjpeg(jpeg-9b)

需要用到的文件&#xff1a; jpeg-9b.zip win32.mak 下载链接链接&#xff1a;https://pan.baidu.com/s/1Z0fwbi74-ZSMjSej-0dV2A 提取码&#xff1a;huhu 步骤1&#xff1a;下载并解压jpeg-9b。 这里把jpeg-9b解压到文件夹"D:\build-libs\jpeg\build\jpeg-9b" …

CVE-2022-22965 Spring Framework远程命令执行

0x01 影响版本 Spring Framework < 5.3.18 Spring Framework < 5.2.20 JDK>9 0x02 复现环境 vulhub/spring/cve-2022-22965 0x03 漏洞复现 首先docker-compose up -d开启靶场 输入payload <%if("j".equals(request.getParameter("pwd")…

LSM树原理详解

LSM树(Log-Structured-Merge-Tree)的名字往往会给初识者一个错误的印象&#xff0c;事实上&#xff0c;LSM树并不像B树、红黑树一样是一颗严格的树状数据结构&#xff0c;它其实是一种存储结构&#xff0c;目前HBase,LevelDB,RocksDB这些NoSQL存储都是采用的LSM树。 LSM树的核…

如何在用pip配置文件设置HTTP爬虫IP

首先&#xff0c;定义问题&#xff1a;在 Pip 中设置HTTP爬虫IP服务器&#xff0c;以便在网络上进行访问和下载。 亲身经验&#xff1a;我曾经遇到过类似问题&#xff0c;通过设置HTTP爬虫IP服务器成功解决了网络访问问题。 数据和引证&#xff1a;根据 pip 官方文档&#xff…

小程序如何设置自取规则

​在小程序中&#xff0c;自取规则是指当客户下单时选择无需配送的情况下&#xff0c;如何设置相关的计费方式、指定时段费用、免费金额、预定时间和起取金额。下面将详细介绍如何设置这些规则&#xff0c;以便更好地满足客户的需求。 在小程序管理员后台->配送设置->自…

0基础学习PyFlink——用户自定义函数之UDTAF

大纲 UDTAFTableAggregateFunction的实现累加器定义创建累加 返回类型计算 完整代码 在前面几篇文章中&#xff0c;我们分别介绍了UDF、UDTF和UDAF这三种用户自定义函数。本节我们将介绍最后一种函数&#xff1a;UDTAF——用户自定义表值聚合函数。 UDTAF UDTAF函数即具备了…

什么是腾讯云轻量应用服务器?轻量性能和价格表分享

腾讯云轻量应用服务器怎么样&#xff1f;什么是腾讯云轻量应用服务器&#xff1f;轻量应用服务器性能怎么样&#xff1f;腾讯云轻量应用服务器如何收费&#xff1f;轻量2核2G3M云服务器88元一年、3年轻量2核2G4M带宽优惠价366.6元、轻量2核4G5M服务器166.6元一年、3年轻量2核4G…

【Javascript】ajax(阿甲克斯)

目录 什么是ajax? 同步与异步 原理 注意 写一个ajax请求 创建ajax对象 设置请求方式和地址 发送请求 设置响应HTTP请求状态变化的函数 什么是ajax? 是基于javascript的一种用于创建快速动态网页的技术&#xff0c;是一种在无需重新加载整个网页的情况下&#xff0c…

计算机网络【CN】IPV4报文格式

版本&#xff08;4bit&#xff09;&#xff1a;IPV4/IPV6首部长度&#xff08;4bit&#xff09;&#xff1a;标识首部的长度 单位是4B最小为&#xff1a;20B最大为&#xff1a;60&#xff08;15*4&#xff09;B总长度&#xff08;16bit&#xff09;&#xff1a;整个数据报&…

vue使用smooth-signature实现移动端电子签字,包括横竖屏

vue使用smooth-signature实现移动端电子签字&#xff0c;包括横竖屏 1.使用smooth-signature npm install --save smooth-signature二.页面引入插件 import SmoothSignature from "smooth-signature";三.实现效果 四.完整代码 <template><div class&quo…

LVS集群-DR模式

概念&#xff1a; LVS-DR模式&#xff0c;也是最常用的lVS负载方式&#xff0c;DR DIRECT ROUTING 直接路由模式 负载均衡器lVS调度器&#xff0c;只负责请求和转发到后端的真实服务器&#xff0c;但是影响结果&#xff0c;由后端服务器直接转发给客户端&#xff0c;不需要经…

2023年第四届MathorCup大数据竞赛(A题)|坑洼道路检测和识别|数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2021年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 希望这些想法对大家的做题有一定的启发和借鉴意义。 让我们来…

LLM系列 | 22 : Code Llama实战(下篇):本地部署、量化及GPT-4对比

引言 模型简介 依赖安装 模型inference 代码补全 4-bit版模型 代码填充 指令编码 Code Llama vs ChatGPT vs GPT4 小结 引言 青山隐隐水迢迢&#xff0c;秋尽江南草未凋。 小伙伴们好&#xff0c;我是《小窗幽记机器学习》的小编&#xff1a;卖热干面的小女孩。紧接…

微信小程序设计之主体文件app-ts/js

一、新建一个项目 首先&#xff0c;下载微信小程序开发工具&#xff0c;具体下载方式可以参考文章《微信小程序开发者工具下载》。 然后&#xff0c;注册小程序账号&#xff0c;具体注册方法&#xff0c;可以参考文章《微信小程序个人账号申请和配置详细教程》。 在得到了测…

新的iLeakage攻击从Apple Safari窃取电子邮件和密码

图片 导语&#xff1a;学术研究人员开发出一种新的推测性侧信道攻击&#xff0c;名为iLeakage&#xff0c;可在所有最新的Apple设备上运行&#xff0c;并从Safari浏览器中提取敏感信息。 攻击概述 iLeakage是一种新型的推测性执行攻击&#xff0c;针对的是Apple Silicon CPU和…

简单了解一下:NodeJS的WebSocket网络编程

NodeJS的webSocket网络编程。 那什么是WebSocket呢&#xff1f;WebSocket是HTML5提供的一种浏览器和服务器进行通信的网络技术。两者之间&#xff0c;只需要做一个握手动作&#xff0c;就可以在浏览器和服务器之间开启一条通道&#xff0c;就可以进行数据相互传输。 实现WebS…

c++的4中类型转换操作符(static_cast,reinterpret_cast,dynamic_cast,const_cast),RTTI

目录 引入 介绍 static_cast 介绍 使用 reinterpret_cast 介绍 使用 const_cast 介绍 使用 dynamic_cast 介绍 使用 RTTI(运行时确定类型) 介绍 typeid运算符 dynamic_cast运算符 type_info类 引入 原本在c中,我们就已经接触到了很多类型转换 -- 隐式类型转…

线程安全问题

线程安全 简单来说&#xff0c;在多个线程访问某个方法或者对象的时候&#xff0c;不管通过任何的方式调用以及线程如何去交替执行。在程序中不做任何同步干预操作的情况下&#xff0c;这个方法或者对象的执行/修改都能按照预期的结果来反馈&#xff0c;那么这个类就是线程安全…