出自–南昌理工学院ACM集训队
对于dfs二三认识
problem 1036 选数
题目链接 洛谷p1036
Problem Description
已知 n个整数 x1,x2,…,xn,以及1个整数k(k<n)。从n个整数中任选k个整数相加,可分别得到一系列的和。例如当n=4,k=3n=4,k=3n=4,k=3,444个整数分别为3,7,12,193,7,12,193,7,12,19时,可得全部的组合与它们的和为:
3+7+12=22
3+7+19=29
7+12+19=38
3+12+19=34
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29
输入格式
键盘输入,格式为:
n,k(1≤n≤20,k<n)
x1,x2,…,xn(1≤xi≤5000000)
输出格式
屏幕输出,格式为: 1个整数(满足条件的种数)。
输入输出样例
输入 #1
4 3
3 7 12 19
输出 #1
1
题目大意:就从n个数中选择m个数,构成素数的种类有多少
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
int a[maxn],ans=0;
int vis[maxn];
int k,n,num=0;
bool isprime(int x)
{
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
return false;
}
return true;
}
void dfs(int depth)
{
if(depth==k)
{
if(isprime(ans))
{
num++;
//cout<<ans<<endl;
}
}
else
{
for(int i=1;i<=n;i++)
{
if(!vis[i]&&i>depth)
{
vis[i]=1;
ans+=a[i];
//cout<<ans<<endl;
dfs(depth+1);
//cout<<ans<<endl;
vis[i]=0;
ans-=a[i];
}
}
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
dfs(0);
cout<<num<<endl;
return 0;
}
自信的我以为可以过,结果冷冷的冰雨在脸上拍,火辣的疼,结果和我的预期严重不符这是为什么呢?,不急,在这里推荐先一个检查错误的方法
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
int a[maxn],ans=0;
int vis[maxn],b[maxn];
int k,n,num=0;
bool isprime(int x)
{
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
return false;
}
return true;
}
void dfs(int depth)
{
if(depth==k)
{
if(isprime(ans))
{
num++;
for(int i=0;i<depth;i++)
printf("%d ",b[i]);
printf("\n");//将检查的数全部输出
}
}
else
{
for(int i=1;i<=n;i++)
{
if(!vis[i]&&i>depth)
{
vis[i]=1;
ans+=a[i];
b[depth]=a[i];//用于检查加了那些数;
dfs(depth+1);
vis[i]=0;
ans-=a[i];
}
}
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
dfs(0);
cout<<num<<endl;
return 0;
}
经过测试发现了问题
错解:正解
仔细一对比,发现其实之前的代码之所以出现问题的原因是i每次是从1开始这样会重覆选择,就是我选择这个数,那我就只能选择后面的数,上代码仔细体会
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
int a[maxn],ans=0;//ans用来判断加起来的和
int vis[maxn],b[maxn];
int k,n,num=0,y=0;//num用来记录种类数,
bool isprime(int x)//用ans来判断是否为素数
{
for(int i=2;i*i<=x;i++)
{
if(x%i==0)
return false;
}
return true;
}
void dfs(int depth,int y)
{
int i;
if(depth==k)//如果是k个数就进入判断一下是否为素数
{
if(isprime(ans))
{
num++;
return;
}
}
else
{
y++;
for(i=y;i<=n;i++)//从它之后的都能选
{
if(!vis[i])
{
vis[i]=1;
ans+=a[i];
dfs(depth+1,i);
vis[i]=0;
ans-=a[i];//这两句是为了清空之前选的那个数
}
}
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i];
dfs(0,0);
cout<<num<<endl;
return 0;
}