https://www.luogu.com.cn/problem/P1036
方法一:递归回溯+素数判断
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n, k, ans=0; 4 int x[25], a[25]; 5 bool vis[25]; 6 bool is_prime(int p){ 7 if(p<2)return 0; 8 for(int i=2; i<=sqrt(p); i++) 9 if(p%i==0)return 0; 10 return 1; 11 } 12 void dfs(int step) 13 { 14 if(step>k){ 15 int sum=0; 16 //for(int i=1; i<=k; i++)cout<<a[i]<<" "; 17 for(int i=1; i<=k; i++)sum+=x[a[i]];//对应序号的数值 18 if(is_prime(sum))ans++; 19 return; 20 } 21 for(int i=a[step-1]+1; i<=n; i++) 22 { 23 if(!vis[i]) 24 { 25 a[step]=i; 26 vis[i]=1; 27 dfs(step+1); 28 vis[i]=0; 29 } 30 } 31 32 } 33 int main() 34 { 35 36 cin>>n>>k; 37 for(int i=1; i<=n; i++) 38 cin>>x[i]; 39 dfs(1); 40 cout<<ans; 41 return 0; 42 }
以上方法首先要熟练用递归写出“组合”,注意跟全排列的差异在21行,前提知识请查看 》全排列+组合数
方法二:二进制枚举+素数筛
1 #include<bits/stdc++.h> 2 using namespace std; 3 int a[25]; 4 const int max_n=10000005; 5 int b[max_n]; 6 void su(){//素数筛 建立表供后面查 7 b[1]=1; 8 int m=sqrt(max_n); 9 for(int i=2; i<=m; i++) 10 if(!b[i]) 11 for(int j=2; j<=max_n/i; j++) 12 b[i*j]=1; 13 // for(int i=2; i<100; i++) 14 // if(!b[i]) 15 // cout<<i<<" "; 16 } 17 int main() 18 { 19 su(); 20 int n, m, ans=0; 21 cin>>n>>m; 22 for(int i=0; i<n; i++)cin>>a[i];//输入 23 for(int i=0; i<(1<<n); i++){ 24 int sum=0; 25 int num=0, kk=i;//num统计i中1的个数;kk用来处理i 26 while(kk){ 27 kk=kk&(kk-1);//清除kk中的最后一个1 28 num++;//统计1的个数 29 } 30 31 if(num==m){//二进制数中的1有k个,符合条件 32 for(int j=0; j<n; j++) 33 if(i&(1<<j)) 34 sum+=a[j];//cout<<a[j]<<" "; 35 36 if(!b[sum])ans++;//判断sum是否为素数 37 } 38 } 39 cout<<ans; 40 return 0; 41 }
以上方法看不懂的请参考笔者之前写过的一篇博客》》重写--全排列--全面理解搜索
方法三:递归(摘自洛谷题解)
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 bool isprime(int a){//判断素数 6 /*0和1特判真的没啥用对这题 7 吐槽:题中n的数据范围很奇怪, 8 n还有可能=1.....那k<n...... 9 */ 10 for(int i = 2;i * i <= a; i++)//不想用sqrt,还要头文件 11 if(a % i == 0)//如果整除 12 return false;//扔回false 13 //程序都到这里的话就说明此为素数 14 //否则就被扔回了 15 return true;//扔回true 16 } 17 18 int n,k; 19 int a[25]; 20 long long ans; 21 22 void dfs(int m, int sum, int startx){//最重要的递归 23 //m代表现在选择了多少个数 24 //sum表示当前的和 25 //startx表示升序排列,以免算重 26 if(m == k){//如果选完了的话 27 if(isprime(sum))//如果和是素数 28 ans++;//ans加一 29 return ; 30 } 31 for(int i = startx; i < n; i++) 32 dfs(m + 1, sum + a[i], i + 1);//递归 33 //步数要加一,和也要加 34 //升序起始值要变成i+1,以免算重 35 return ;//这一个步骤下,所有的都枚举完了 36 //直接返回去 37 } 38 39 int main(){ 40 scanf("%d%d",&n,&k);//输入 41 42 for(int i = 0; i < n; i++) 43 scanf("%d",&a[i]);//循环读入 44 dfs(0,0,0);//调用函数 45 printf("%d ",ans);//输出答案 46 return 0;//结束程序 47 }