杂记浅谈

出自–南昌理工学院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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值