利用stl解决全排列问题

组合数学中经常用到排列,作为c++中stl的库函数next_permutation(start,end),和prev_permutation(start,end)。这两个函数作用是一样的,区别就在于前者求的是当前排列的下一个排列,后一个求的是当前排列的上一个排列。至于这里的“前一个”和“后一个”,我们可以把它理解为序列的字典序的前后,严格来讲,就是对于当前序列pn,他的下一个序列pn+1满足:不存在另外的序列pm,使pn<pm<pn+1.

为了充分理解和利用,我们看一个题目

题目

还是上周的题目吧

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

这里给个链接

分析及解决

然后首先是基础的输出排列,我们可以看到简洁的代码就可以解决上周BFS才能解决的问题

#include<bits/stdc++.h>
using namespace std;
int main (){
	int data[4]={5,2,1,4};
	sort (data,data+4);
	do{
		for (int i=0;i<4;i++)
		cout <<data[i] << " ";
		cout << endl;
	}while (next_permutation(data,data+4));
	return 0;
} 

接下来我们可以利用这个进行对n个数字选k个进行相加然后输出

	if(begin==m){
	
	for (int i=0;i<m;i++){
		sum=sum+data[i];
	
	}

很简单就利用这个简单的for循环就可以得出和

接下来就只需要将所得的和放入一个判断是否素数的函数

int prime(int n)
{
	int i;
	if (n < 2) {
		
	}
	else {
		for (i = 2; i < n; i++) {//判断n在2~n-1中有没有因数
			if (n%i == 0)//如果用可以除尽的数,则非素数
				break;
		}
		if (i < n) {//存在2~n-1之间有因数
		
		}
		else
			cnt++;	
	}
	return 0;
}

接下来还有一节非常重要的事情

因为题目需要的是不需要重复,而我们所写的是全排列,所以还需要除m的阶乘才能合理

最后附上我的ac代码(写的比较丑陋繁琐,肯定有更好的)

#include <bits/stdc++.h>
using namespace std;
#define swap(a,b){int temp=a;a=b;b=temp;} 
int n,m;
int cnt=0;
int data[1001];

int prime(int n)
{
	int i;
	if (n < 2) {
		
	}
	else {
		for (i = 2; i < n; i++) {//判断n在2~n-1中有没有因数
			if (n%i == 0)//如果用可以除尽的数,则非素数
				break;
		}
		if (i < n) {//存在2~n-1之间有因数
		
		}
		else
			cnt++;	
	}
	return 0;
}

int perm(int begin,int end){
	int i;
	int sum=0;
	if(begin==m){
	
	for (int i=0;i<m;i++){
		sum=sum+data[i];
	
	}
	//	cout << sum << endl;
	prime(sum);
	sum=0;
		
}
	else
	for(i=begin;i<=end;i++){
		swap(data[begin],data[i]);
		perm(begin+1,end);
		swap(data[begin],data[i]);
	} 
}
int main(){
	cin >> n >> m;
	getchar();
	for (int i=0;i<n;i++){
		cin >> data[i];
	}
	perm(0,n-1);
	int p=1;
	for(int i=m;i>0;i--){
		p=p*i;
	}

	cout << cnt/p << endl;
}

总结

最后合理的利用stl可以更快更方便的解决问题   所以也觉得自己有必要系统的学习stl的内容

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值