当前位置: 首页 > news >正文

完全数和质数算法详解

完全数是指一个正整数,它等于其所有真约数(即除了自身以外的所有正因数)之和。例如,6 是一个完全数,因为它的真约数是 1、2 和 3,且 1 + 2 + 3 = 6。

1 计算约数和

1.1 遍历

遍历其所有可能的约数并计算它们的和。如果和等于该数,则为完全数,否则不是。

#include <iostream>
using namespace std;

int main() {
    int N;
    cin >> N;
    while (N--) {
        int X;
        cin >> X;
        int sum = 0;
        for (int i = 1; i * i <= X; ++i) {
            if (X % i == 0) {
                if (i != X) sum += i; 
                int j = X / i;
                if (j != X && j != i) sum += j; 
            }
        }
        cout << X << (sum == X ? " is" : " is not") << endl;
    }
    return 0;
}

1.2 生成表

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

int main() {
    int N;
    cin >> N;
    vector<int> perfect = {6, 28, 496, 8128, 33550336}; 
    while (N--) {
        int X;
        cin >> X;
        bool isPerfect = false;
        for (int num : perfect) {
            if (num == X) {
                isPerfect = true;
                break;
            }
        }
        cout << X << (isPerfect ? " is" : " is not") << endl;
    }
    return 0;
}

2 判断质数

2.1 错误解法 遍历

#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    for (int j = 1; j <= n; j++) {
        int x;
        bool is_prime = true;
        cin >> x;
        if (x == 1) 
            cout << x << " is not" << endl;
        else {
            int i;
            for (i = 2; i < x; i++) {
                if (x % i == 0) {
                    is_prime = false;
                    break;
                } else 
                    is_prime = true;
            }
            if (is_prime) 
                cout << x << " is" << endl;
            else 
                cout << x << " is not" << endl;
        }
    }
    return 0;
}

时间复杂度:对于每个输入的数字 x x x,内层循环从 2 2 2 x − 1 x-1 x1 遍历,因此单次判定的时间复杂度为 O ( x ) O(x) O(x)。如果需要判断 N N N 个数字,则总时间复杂度为 O ( N ⋅ X ) O(N \cdot X) O(NX),其中 X X X 是输入数字的最大值。当 X X X 较大(例如 1 0 9 10^9 109)时,通常会TLE


2.2 正确解法

根据数学原理,一个数 x x x 如果不是质数,那么它一定可以分解为两个因数 a a a b b b,且至少有一个因数小于等于 x \sqrt{x} x 。因此,我们只需要检查从 2 2 2 x \sqrt{x} x 的所有整数即可。

#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    while (n--) {
        int x;
        bool is_prime = true;
        cin >> x;
        if (x == 1) 
            cout << x << " is not " << endl;
        else {
            int i;
            for (i = 2; i <= x / i; i++) {
                if (x % i == 0) {
                    is_prime = false;
                    break;
                }
            }
            if (is_prime) 
                cout << x << " is " << endl;
            else 
                cout << x << " is not " << endl;
        }
    }
    return 0;
}

时间复杂度: 对于每个数字 x x x,只需检查从 2 2 2 x \sqrt{x} x 的所有整数,因此单次判定的时间复杂度为 O ( x ) O(\sqrt{x}) O(x )。如果需要判断 N N N 个数字,则总时间复杂度为 O ( N ⋅ X ) O(N \cdot \sqrt{X}) O(NX ),其中 X X X 是输入数字的最大值。


为什么只需要检查到 x \sqrt{x} x

如果一个数 x x x不是质数,那么它一定可以分解为两个因数 a a a b b b,且至少有一个因数小于或等于 x \sqrt{x} x

一个数 x x x合数(非质数),意味着它可以被分解为两个整数的乘积: x = a ⋅ b x=a\cdot b x=ab,其中 a a a b b b都是大于1的整数。如果 x x x是质数,则它无法被任何小于 x x x的正整数整除(除了1和自身)。

假设 x x x是一个合数,那么它可以写成两个因数的乘积:
x = a ⋅ b x=a\cdot b x=ab
其中 a a a b b b都是正整数,且 a ≤ b a\leq b ab(为了简化讨论,我们可以假设 a a a是较小的那个因数)。
a ⋅ b = x    ⟹    a ≤ x 或 b ≤ x a\cdot b=x\implies a\leq\sqrt{x}\quad\text{或}\quad b\leq\sqrt{x} ab=xax bx

因为如果 a > x a>\sqrt{x} a>x b > x b>\sqrt{x} b>x ,那么 a ⋅ b > x ⋅ x = x a\cdot b>\sqrt{x}\cdot\sqrt{x}=x ab>x x =x,这与 a ⋅ b = x a\cdot b=x ab=x矛盾。因此,至少有一个因数 a a a b b b满足 a ≤ x a\leq\sqrt{x} ax b ≤ x b\leq\sqrt{x} bx 。换句话说,如果 x x x是合数,那么它一定存在一个小于或等于 x \sqrt{x} x 的因数。


反证法:

如果 x x x是合数,则它一定存在一个小于或等于 x \sqrt{x} x 的因数。

证明

  1. 假设 x x x是合数,且 x x x的所有因数都大于 x \sqrt{x} x
  2. x = a ⋅ b x=a\cdot b x=ab,其中 a a a b b b都是大于 x \sqrt{x} x 的整数。
  3. 根据假设, a > x a>\sqrt{x} a>x b > x b>\sqrt{x} b>x
  4. 因此, a ⋅ b > x ⋅ x = x a\cdot b>\sqrt{x}\cdot\sqrt{x}=x ab>x x =x,这与 x = a ⋅ b x=a\cdot b x=ab矛盾。
  5. 故假设不成立,即 x x x至少存在一个小于或等于 x \sqrt{x} x 的因数。

示例分析:

正例 x = 36 x=36 x=36

36 = 6 ⋅ 6 36=6\cdot6 36=66,其中 6 = 36 6=\sqrt{36} 6=36 。所有因数对为 ( 1 , 36 ) , ( 2 , 18 ) , ( 3 , 12 ) , ( 4 , 9 ) , ( 6 , 6 ) (1,36),(2,18),(3,12),(4,9),(6,6) (1,36),(2,18),(3,12),(4,9),(6,6)。只需要检查 2 , 3 , 4 , 5 , 6 2,3,4,5,6 2,3,4,5,6即可找到因数。

反例 x = 73 x=73 x=73

73 73 73是质数,无法分解为两个整数的乘积。检查 2 , 3 , 4 , 5 , 6 , 7 , 8 2,3,4,5,6,7,8 2,3,4,5,6,7,8后发现 73 73 73无法被整除。

相关文章:

  • PHP代驾系统小程序
  • 力扣LeetCode: 1552 两球之间的磁力
  • 【java】基本数据类型和引用数据类型
  • deepseek+即梦一键生成海报
  • 上海正控ZK880 变频器基本操作
  • linux概念详解
  • 机器学习实战(1): 入门——什么是机器学习
  • SpringBoot 笔记
  • 【开源免费】基于SpringBoot+Vue.JS文理医院预约挂号系统(JAVA毕业设计)
  • 3.3 企业级AI Agent工程实践:从API设计到高可用架构的全栈开发指南
  • 1170. 比较字符串最小字母出现频次
  • 向量元素间是否相等mask矩阵
  • 《Foundation 起步》
  • Linux系统常用命令用法详解
  • 【ROS2】RViz2源码分析(七):DisplaysPanel 中的树状模型/视图
  • 网页五子棋——用户模块
  • Spring Boot 整合 Keycloak
  • 【计算机网络】TCP三次握手
  • GeekPad智慧屏编程控制(三)
  • 光谱相机在天文学领域的应用
  • 新华每日电讯:博物馆正以可亲可近替代“高冷范儿”
  • 原核试验基地司令员范如玉逝世,从事核试验研究超40年
  • 美联储官员:美国经济增速可能放缓,现行关税政策仍将导致物价上涨
  • 国家统计局向多省份反馈统计督察意见
  • 互降关税后,从中国至美国的集装箱运输预订量飙升近300%
  • 跨文化戏剧的拓荒者与传承者——洪深与复旦剧社的百年回响