10. 最大公约数&最小公倍数&加法原理&乘法原理&排列组合

10. 最大公约数&最小公倍数&加法原理&乘法原理&排列组合

约数&倍数

约数,又称因数或因子。
整数 a 除以整数 b(b≠0) 除得的商正好是整数而没有余数,我们就说 a 能被 b 整除,或 b 能整除 a,记作:b|a。
a 称为 b 的倍数,b 称为 a 的约数。

在自然数(0和正整数)的范围内,任何正整数都是 0 的约数。
注意:一个数的约数必然包括1及其本身。

问:24的约数有哪些?

1 2 3 4 6 8 12 24

在大学之前,"约数"一词所指的一般只限于正约数。
约数和倍数都是二元关系的概念,不能孤立地说某个整数是约数或倍数。
一个整数的约数是有限的。同时,它可以在特定情况下成为公约数。
如果一个数 c 既是数 a 的因数,又是数 b 的因数,那么 c 叫做 a 与 b 的公因数/公约数。
两个数的公约数中最大的一个,叫做这两个数的最大公约数,如:

12 的约数有:1 2 3 4 6 12
24 的约数有:1 2 3 4 6 8 12 24
则 12 与 24 的公约数有:1 2 3 4 6 12。
其中 12 是最大的,我们就称 12 为两者的最大公约数。

倍数:当 a/b=q...r(r=0)时,称 a 为 b 的倍数,记做: b|a。

公倍数:两个数的公共倍数,如:

12 的倍数有:12 24 36 48 ...
24 的倍数有:24 48 72 96 ...
显而易见,12 与24 的倍数都是无限的,且具有无限的公倍数:24 48 ...
其中 24 是最小的,我们就称 24 为两者的最小公倍数。

那么如果让你来分析 任意两个数的最大公约数与最小公倍数,有信心吗?

【题目描述】输入 a,b, 求他们的最大公约数与最小公倍数。
【输入样例】12 20
【输出样例】4 60

先自己思考吧!
相信你可以想到不止一种解法!


求最大公约数的三种方法:

  1. 最小递减法
    先找 a,b 的最小值,判断该值能否同时被 a,b 整除,如果可以该数就是答案,否则每次-1,继续判断,直到找到答案。
int gcd(int a, int b){
    for(int i=min(a,b); i>=1; i--){
        if(a%i==0 && b%i==0) return i;
    }
}
  1. 更相减损法
    a-b=c,则 a,b 的最大公约数就是 b,c 的最大公约数,如果 c=0,a 就是答案。
int gcd(int a, int b){
    if(a<b) swap(a, b);
    if(b==0) return a;
    return gcd2(b,a-b);
}
  1. 辗转相除法
    a/b=q...r,则 a,b 的最大公约数就是 b,r 的最大公约数,如果 r=0,则 b 就是答案。
int gcd(int a, int b){
    if(b==0) return a;
    return gcd(b, a%b);
}

求最小公倍数的两种方法:

  1. 最大递增法
    先找 a,b 的最大值,判断该值能否同时整除 a,b,如果可以该数就是答案,否则每次+1,继续判断,直到找到答案。
int lcm(int a, int b){
    for(int i=max(a,b); i<=a*b; i++){
        if(i%a==0 && i%b==0) return i;
    }
}
  1. 定理法:两个数的乘积等于这两个数的最大公约数与最小公倍数的乘积。
int lcm(int a, int b){
    return a*b/gcd(a,b);
}

辗转相除法&更相减损法的证明,点击跳转

#include<cstdio>
//最小递减法求最大公约数
int gcd1(int a, int b){
    for(int i=min(a,b); i>=1; i--){
        if(a%i==0 && b%i==0) return i;
    }
    return 1;
}
//更相减损法求最大公约数
int gcd2(int a, int b){
    if(a<b) swap(a, b);
    if(b==0) return a;
    return gcd2(b,a-b);
}
//辗转相除法求最大公约数
int gcd3(int a, int b){
    if(b==0) return a;
    return gcd3(b, a%b);
}

//最大递增法求最小公倍数
int lcm1(int a, int b){
    for(int i=max(a,b); ; i++){
        if(i%a==0 && i%b==0) return i;
    }
}
//定理法:两个数的乘积等于这两个数的最大公约数与最小公倍数的乘积
int lcm2(int a, int b){
    return a*b/gcd3(a,b);
}
int main(){
    int a,b; scanf("%d%d", &a, &b);

    printf("gcd1(%d,%d) = %d\n", a, b, gcd1(a,b));
    printf("gcd2(%d,%d) = %d\n", a, b, gcd2(a,b));
    printf("gcd3(%d,%d) = %d\n", a, b, gcd3(a,b));
    printf("lcm1(%d,%d) = %d\n", a, b, lcm1(a,b));
    printf("lcm2(%d,%d) = %d\n", a, b, lcm2(a,b));
    return 0;
}

输入:12 20
输出:
gcd1(12,20) = 4
gcd2(12,20) = 4
gcd3(12,20) = 4
lcm1(12,20) = 60
lcm2(12,20) = 60

问题描述:a/b + c/d = e/f (0<a,b,c,d<100).

输入格式:a b c d
输出格式:e/f 的最简式,如果 f=1, 则输出 e.

输入样例:1 2 3 4
输出样例:5/4

输入样例:2 2 4 2
输出样例:3

  • 参考程序
#include<iostream>
using namespace std;
int gcd(int a,int b){
    if(b==0) return a;
    return gcd(b, a%b);
}
int main(){
    int a,b,c,d; cin>>a>>b>>c>>d;
    int e=a*d+b*c, f=b*d;
    int temp = gcd(e, f);
    e = e/temp, f = f/temp;

    if(f!=1) cout<<e<<"/"<<f<<endl;
    else cout<<e<<endl;
    return 0;
}

加法原理&乘法原理

  • 加法原理
    做一件事,完成它有 N 类办法,在第一类办法中有 M1 种不同的方法,在第二类办法中有 M2 中不同的办法,……,在第 n 类办法中有 Mn 种不同的方法,那么完成这件事共有 M1+M2+..+Mn 种不同方法,每一种方法都能达成目标。

例如:Hacker 一家人外出旅游,可以乘火车,也可以乘汽车,还可以坐飞机。
经过网上查询,出发那一天中火车有4班,汽车有3班,飞机有2班
根据加法原理,任意选择其中一个班次的方法为4+3+2=9(种)。

  • 乘法原理:
    做一件事,完成它需要分成 n 个步骤,做第一步有 M1 中不同的方法,做第二步有 M2 中不同的方法,……,做第 n 步有 Mn 中不同的方法,那么完成这件事共有 M1*M2*…*Mn 种不同的方法。

例如:从甲地到乙地有 2 条路,从乙地到丙地有 3 条路,从丙路到丁地有 2 条路。
问:从甲地到丁地,共有多少种不同的走法?
根据乘法原理,共有2*3*2=12种走法。

排列组合

排列:是指按座位顺序排列,有先后顺序之分,比如:

现要 5 名同学坐在 3 个椅子上,每名同学各不相同,各个椅子不同,问有多少种落座方案?

可以想到:第 1 个椅子可以落座 5 人,第 2 个椅子可以落座 4 人,第 3 个椅子可以落座 3 人;
根据乘法原理可以计算落座方案数 N = 5*4*3 = 60。

那么这样的算法我们可以使用排列公式 \(A(n,m) = A_n^m = \frac{n!}{(n-m)!}\),表示从 n 个人中选择 m 个人进行排列,有先后顺序之分。

A(5,3) = 5!/(5-3)! = 5*4*3=60

组合:是指按座位数量任意落座,无先后顺序之分,比如:

现要 5 名同学坐在 3 个椅子上,每名同学各不相同,各个椅子相同,问有多少种落座方案?

可以想到:由于只有 3 个椅子,那么问题转化为 从 5 个同学中选择 3 个同学进行组合。

那么如果先任选 3 个同学,A(5, 3) = 60,但是这样会有重复情况,于是除去重复次数 3! 即可。

那么这样的算法我们可以使用组合公式 \(C(n,m) = C_n^m = \frac{n!}{m!*(n-m)!}\),表示从 n 个人中选择 m 个人进行组合,无先后顺序之分。

C(5,3) = A(5,3)/A(3,3) = 5!/2!/3! = 10
  • 公式
A(n, m) = n!/(n-m)!
A(n, 1) = n
C(n, m) = A(n, m)/A(m, m) = n!/(n-m)!/m!
C(n, m) = C(n, n-m)
C(n, 0) = C(n, n) = 1

可以把从n个数中选m个数的组合分为 2 类

1. 不含第n个数的组合,方案数为:C(n-1, m)
2. 含第n个数的组合,方案数为:C(n-1, m-1)
   所以C(n, m) = C(n-1, m)+C(n-1, m-1)

参考文章:

数学:排列组合,点击跳转

posted @ 2022-05-31 10:18  HelloHeBin  阅读(550)  评论(0编辑  收藏  举报