洛谷P1036 选数(C++)

题目链接:P1036 [NOIP2002 普及组] 选数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这道题一看就是用到了子集枚举(虽然我不会),但因为站内很多大佬发过,所以我就去学了学,例如,拿题目给出的样例来看,用0或1代表是否在子集内,4代表4个数,若四个数都在,即1111,若把他当成2进制的数,用10进制表示即为15,所以我们就得到了子集枚举的方法。然后“4个里面挑3个”,即2进制数中应有“3个1”例如1110.

那我们面临的第二个问题就是,3个1怎么找,这里其实c++正好有个函数可以实现这个功能,叫做__builtin_popcount(int n),他的功能就是比如n为15时,他会返回15的二进制形式(1111)中有几个1(没错,就这样就解决了)但是,这个函数,他只是在GCC编译器里才能使用,如果在其他编译器里,可能就没法用了(鼠鼠就是这样子,然后查了半天资料),但是,咱们可以试着模拟实现一下,也不是很复杂。

int popcount(int a) {
	int ans=0;
	while (a != 0) {
		if (a % 2 == 1)
			ans++;
		a=a >> 1;
	}
	return ans;
}

这段代码中右移运算符右移一位就是缩小2倍的意思,如果有左移运算符和右移运算符不懂得同学可以在站内看一些大佬发的博客,讲解非常细致。

接着判断素数,这个很简单

bool check(int x)//判断质数
{
	for (int i = 2; i * i <= x; i++) {
		if (x % i == 0)
			return 0;
	}
	return 1;
}

好的,那么这道题咱们思路就分解完了,接下来在串一下

首先从n中选出k个数,咱们需要求出n的子集个数,然后判断每个子集中元素个数是否等于k,然后若等于k,然后加在一起,接着判断是素数,然后此题得解,接着这是完整代码。

#include<iostream>
#include<cstdio>
#include<bit>
using namespace std;
int a[20];
int popcount(int a) {
	int ans=0;
	while (a != 0) {
		if (a % 2 == 1)
			ans++;
		a=a >> 1;
	}
	return ans;
}
bool check(int x)//判断质数
{
	for (int i = 2; i * i <= x; i++) {
		if (x % i == 0)
			return 0;
	}
	return 1;
}
int main() {
	int n, k,ans=0;
	cin >> n >> k;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	int U = 1 << n;
	for (int S = 0; S < U; S++) {
		if (popcount(S) == k) {
			int sum = 0;
			for (int i = 0; i < n; i++)
				if (S & (1 << i))sum += a[i];
			if (check(sum))ans++;
		}
	}
	cout << ans;
	return 0;
}

对了,代码里还有一个我自认为比较复杂的(鼠鼠不会写,抄书的)

即S & (1 << i)这个就是“判断要加哪个”,比如说“4个里面选3个”,即0111,1011,1101,1110,

这句话的作用就是判断哪里是1,“&”的意思就是与,即0&0=0,0&1=0,1&1=1;然后当i=1时,就是S&1,我们假设S是5,即S为00000101,1为00000001,这俩进行&运算,得到的结果就是00000001,符合条件,然后加上,左移以为后同理1变成2,为00000010,可以判断是否要加第二位。

好的,如果哪里有疑问或者鼠鼠哪里写错了,欢迎指出,要是有帮助的话还请点个赞,谢谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值