P1036 选数

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\n",ans);//输出答案
46     return 0;//结束程序
47 }

 

posted @ 2020-07-14 23:22  TFLSNOI  阅读(230)  评论(0编辑  收藏  举报