【数据结构】POJ3048——最大因数

题目要求

在这里插入图片描述

思路分析

整体的思路为:对测试数据进行遍历,判断每一个数的最大素数因数,并用临时变量来保存,进行比较,最后找到有最大素数因数的那个数。
在对数据进行遍历之前,可以先进行筛素数的操作,下面是三种筛素数的方法。

筛素数

方法一:试除法

该方法是初学时最常用的方法,就是很简单粗暴地对一个数从2开始一直到sqrt(n)试除,判断是否能够整除。

方法二:埃氏筛

该方法的主要思想是:素数的整数倍一定是合数,找到所有的合数,那么剩下的就是素数。代码如下:

vector<bool> primes(20001,ture);  //创建布尔类型的vector容器来标记一个数是否为素数,初始化时假设所有数均为素数
void isPrime()
{
	primes[0]=false;
	primes[1]=false;
	primes[2]=true;  //将确定的先标记
	for(int p=2;p*p<=20000;p++)  //当筛到p=sqrt(20000)时,20000以内的素数一定都被筛出来了
	{
		if(primes[p])
			for(int i=p*p;i<=20000;i+=p)  //找到所有p的整数倍的数,并将其标记为false
				primes[i]=false;
	}
} 

这种筛选方法比试除法的效率高很多,但是在标记合数的时候,会出现重复标记的情况,例如,通过素数2可以将4、6、8、10、12标记为合数,之后通过素数3又会再次标记6、12,通过5会再次标记10.这样的情况有很多,如果能够防止重复标记,就能够提高效率。

方法三:欧拉筛(线性筛)

该方法基于整数唯一分解定理:任何大于1的正整数n都可以分解为有限个素数的乘积;任何合数都有它对应的一个最小质因子,只通过这个最小质因子将其标记,就可以避免重复标记。
代码如下:

vector<bool> primes(20001,true);  //标记
vector<int> v; //用于存储素数
void isPrime()
{
	for(int i=2;i<n;i++)
	{
		if(primes[i])
			v.push_back(i);
		for(int j=0;j<v.size() && i*v[j]<=n;j++)
		{
			primes[i*v[j]]=false;
			if(i%v[j]==0)  break;//如果i能被v[j]整除,说明i*v[j]及之后的数已经被更小的素数筛过了,所以直接跳出循环以提高效率
		}
	}
}

参考b站UP主:T_zhao的讲解视频

题目完整代码

(该代码中的测试数据从“in.txt"文件中读取)

#include<iostream>
#include<fstream>
#include<vector>
using namespace std;

vector<bool>primes(20005, true);
//先进行素数的筛选,利用埃氏筛
void isPrime()
{
	primes[0] = false;
	primes[1] = false;
	primes[2] = true;
	for (int p = 2; p * p <= 20000; p++)
	{
		if (primes[p])
		{
			for (int i = p * p; i <=20000; i += p)
				primes[i] = false;
		}
	}
}

int SearchMax(int x)  //寻找x的最大素数因数
{
	for (int i = x; i >0; i--)
	{
		if (x % i == 0 && primes[i])
			return i;
	}
	return 1;
}
int main()
{
	ifstream ifs;
	ifs.open("in.txt", ios::in);
	if (!ifs.is_open())
		cout << "open file failed!" << endl;

	int t;
	vector<int> v;
	while (ifs >> t)  //读入数据 
	{
		v.push_back(t);
	}
	
	isPrime();   //调用函数进行筛素数 
	
	int n = v[0];  //数据的个数
	
	int max = 1;
	int temp = 0;
	int m = 0;
	for (int i = 1; i <= n; i++)
	{
		temp = SearchMax(v[i]);
		if (temp > max)
		{
			max = temp;
			m = v[i];
		}
	}
	cout << m<<endl;
	ifs.close();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值