二进制枚举算法

二进制:是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”
子集:是一个数学概念:如果集合A的任意一个元素都是集合B的元素,那么集合A称为集合B的子集。
含有N个元素的集合的一切子集的个数为 2^n。简单证明一下:
含有0个元素的子集有C(N,0)个,
含有1个元素的子集有C(N,1)个,
含有2个元素的子集有C(N,2)个,

含有N个元素的子集有C(N,N)个
由二项式系数的性质可得:C(N,0)+C(N,1)+C(N,2)+…+C(N,N)=2^n。

  1. 自学二进制枚举后自己理解

根据我自己的理解来说二进制枚举就是通过二进制只有0和1两个数值来表示其代表的值是否被我们选中。
所解决的问题:他所解决的问题就是已经告诉我们一个固定数量的值或数,并让我们来计算我们能有多少种不同的选择结果。

首先我吗来补充一波知识
按位与运算(&)
A&B(A,B表示十进制数)表示将A,B转换成十进制数进行比较,如:1&0=0;1&1=1;0&0=0;3&5=011&101=001;

移位运算符(<<)
A<<B代表把A转为二进制后向左移B位(在A的二进制数后添加B个0);例如4的二进制为0100,而16转为二进制为010000,所以4<<2=16;从上面的例子可以看出A<<B的值实质上就是A乘以2的B次方,,并且二进制数在其后面添0就表示该二进制数乘以2。
通常认为A<<B比A*B更快,因为前者是更基于底层的操作。

接下来我们就来看一题题目来实战一下吧
锐锐有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。锐锐现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an。锐锐可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,锐锐就可以得到这些物品。现在的问题是,锐锐有多少种不同的选择物品的方式。
输入格式:输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a1,a2……an的值。
输出格式:输出不同的选择物品的方式的数目。
分析:假设输入为
3
20
20
20
那么那么我们就可以很容易的知道这最终输出的结果为3,因为a1,a2,a3都为20
那么此时因为有3个数那么用三位二进制数就可以表示相应的a1,a2,a3是否被选中。

a1a2
00
a3
0

因为这三个数据每个都有0或1两种状态,因此他就有7种转态来表示其不同的选择情况分别为:
a1 a2 a3
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
因此代码为:

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	int number,arg[20],nu=0,sum;
	scanf("%d",&number);
	for(int i =0;i<number;i++) scanf("%d",&arg[i]);//输入每个数值
	for(int i = 0;i<(1<<number);i++){//1<<number表示我们要循环的每一种不同的情况次数
		sum = 0;
		for(int j = 0;j<number;j++)
			if(i&(1<<j)) sum = sum +arg[j];//这里i&(1<<j)就表示每一种不同的数倍选中的状态,若果他为0(表示没被选中)就将他加起来
		if(sum==40) nu++;
		}
	cout<<nu<<endl;
		return 0;
	}

新人第一次写博客,如果有什么错误或不足的地方希望大家指正

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值