组合数学中经常用到排列,作为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的内容