题目详情:
小强最近在学初等数论,老师给他们出了一个课后习题,那就是给你两个正整数A,B(0<A,B<2^60),判断他们的素因子集合是否相同,小强刚接触数论,想了好一会还是没能想出来,你能帮助他吗?
输入描述:
输入包含多组测试数据,每组测试数据包含两个正整数A,B,以文件结束。
输出描述:
对于每组测试数据如果A和B的素因子集合相同则输出“YES”,否则输出“NO”。
答题说明:
输入样例:
2 8
4 9
10 50
输出样例:
YES
NO
YES
【思路分析】:
根据唯一质因子分解定理,任一合数num仅能以一种方式写成如下乘积的形式:num=a1^e1*a2^e2...an^en。其中an为质因子,且an为递增序列,en为an的个数。例如:3000=2^3*3*5^3。
那么如何求素数因子集合呢?
看到有人这样写:
boolean isPrime = true;
for (int i = 2; i <=a; i++) {
if (a%i == 0) { //是A 的因数
//判断是不是质数
isPrime = true;
for (int j = 2; j < i; j++) {
if(i%j==0){
isPrime = false;
}
}
if (isPrime) {
aList.add(i);
}
}
}
从2到num依次取数,先判断是不是num的因子,如果是,再判断该数是否是素数。现在这种实现方式下时间效率是很低的。
改进:
1.从2开始取数i;
2.如果i能整除num,则i是num的因子;
2.1将n=n/i,直到n%i!=0;
3.继续取i,重复第2步直到i*i>num;
4.如果最后num>1,那么num也是原num的素数因子
代码如下:
#include <iostream>
#include <vector>
using namespace std;
void PrimeSet(long long a, vector<int>& set){
for (long long i = 2; i*i <= a; i++){
if (a%i == 0){
set.push_back(i);
while (a%i == 0){
a = a / i;
}
}
}
if (a > 1){
set.push_back(a);
}
}
void main(){
long long a, b;
vector<int> setA, setB;
while (cin >> a >> b){
PrimeSet(a, setA);
PrimeSet(b, setB);
if (setA.size() != setB.size()){
cout << "NO!" << endl;
}
else{
size_t i;
for ( i = 0; i != setA.size(); i++){
if (setA[i] != setB[i]){
cout << "NO!" << endl;
break;
}
}
if (i >= setA.size()){
cout << "Yes!" << endl;
}
}
}
}
【附加】:
这道题原意是求出A和B各自的素数因子集合然后判断它们是否相等,如果值要判断A和B的素数因子集合是否相等,可以这样直接求出A和B的最大公约数GCD,然后看M=A/GCD和N=B/GCD是否都能整除GCD,如果能,那么A和B的素数因子集合相同,否则不同。
#include <iostream>
using namespace std;
long long GCD(long long a, long long b){
if (b == 0)
return a;
return GCD(b, a%b);
}
int main(){
long long a, b;
while (scanf("%lld%lld", &a, &b) != EOF){
long long gcd = GCD(a, b);
if (gcd % (a / gcd) == 0 && gcd % (b / gcd)==0){
printf("YES\n");
}
else{
printf("NO\n");
}
}
return 0;
}