C语言入门算法——最大公约数和最小公倍数问题

题目描述:

输入两个正整数 x0​,y0​,求出满足下列条件的 P,Q 的个数:

  1. P,Q 是正整数。

  2. 要求P,Q 以 x0​ 为最大公约数,以 y0​ 为最小公倍数。

试求:满足条件的所有可能的 P,Q 的个数。

输入格式

一行两个正整数 x0​,y0​。

输出格式

一行一个数,表示求出满足条件的 P,Q 的个数。

输入输出样例

输入 #1

3 60

输出 #1

4

说明/提示

P,Q 有 4 种:

  1. 3,60。
  2. 15,12。
  3. 12,15。
  4. 60,3。

对于 100% 的数据,2≤x0​,y0​≤10^5。

【题目来源】

P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题

思路及部分代码:

1. 求出最大最小

//返回最大值或者最小值
//根据 d 的值返回最大或者最小
int max_min(int a, int b,int d){
    int max, min;
    if(a >= b){
        max = a;
        min = b;
    }
    else{
        max = b;
        min = a;
    }
    if(d == 0) return min;
    else return max;
}

2. 欧几里得算法求最大公约数

        原本想遍历出结果,但时间复杂度太高,所以学习了一下欧几里得算法。

        欧几里得算法(辗转相除法):其基本思想是用较大的数除以较小的数,然后用较小的数去除余数,再用新的余数去除小的数,如此反复,直到余数为零为止,此时除数就是最大公约数。

//求出最大公约数
/*
欧几里得算法(辗转相除法),其基本思想是用较大的数除以较小的数,
然后用较小的数去除余数,再用新的余数去除小的数,如此反复,
直到余数为零为止,此时除数就是最大公约数。具体步骤如下:
*/
int Common_divisor_max(int x, int y){
    int max = max_min(x,y,1);   //求出最大数
    int c_n = x+y-max;  //除数
    int c = max % c_n;    //被除数
    while(c != 0){
        int di = c; //除数被除数交换
        c = c_n;
        c_n = di;
        c = c % c_n;
    }
    return c_n;
    /*
    for(int i = max;i >= 1;i--){
        if(x%i == 0 && y%i == 0){   //满足最大公约数
            return i;
        }
    }
    */
    //return 0;
}

3. 最小公倍数

        也是考虑到时间复杂度问题,把遍历改成利用公约数求公倍数。

        关系:两个数的乘积等于它们的最大公约数与最小公倍数的乘积。

//求出最小公倍数
int Common_multiple_min(int x,int y,int yue){

    return x*y/yue;

    /*
    int max = max_min(x,y,1);   //求出最大数
    for(int i = max; i<= x*y;i = i + yue){
        if(i%x == 0 && i%y == 0){
            return i;
        }
    }
    */
    //return -1;  //错误
}

4. 思路遍历

        a.  我们知道在P/Q是在输入的x,y中,所以这里给出了一个范围。

        b.  但在实际情况下我们所P/Q的遍历有太多的无用值,浪费我们的计算时间。

        c.  我们由最小公倍数中的关系可得一个判定方式。

        d.  再在我们的函数中,可以根据最大公约数与X再进行一次判定,最后再与Y判定。

P = max_min(x,y, 0);
Q = max_min(x,y, 1);
    
int cnt = 0;    //计数满足要求的Q P
for(int i = P; i <= Q; i = i + x){
    //遍历方式求解,时间复杂度太高
    for(int j = Q; j >= P; j= j - x){
        if(j*i == x*y){
            int yue = Common_divisor_max(i, j);
            if(yue != x)   ;//跳过
            else if(Common_multiple_min(i,j, yue) == y){
                cnt++;
                //printf("P = %d   Q = %d \r\n", i,j);
            }
        }  
    }
}

总代码:

#include <stdio.h>


//返回最大值或者最小值
int max_min(int a, int b,int d){
    int max, min;
    if(a >= b){
        max = a;
        min = b;
    }
    else{
        max = b;
        min = a;
    }
    if(d == 0) return min;
    else return max;
}


//求出最大公约数
/*
欧几里得算法(辗转相除法),其基本思想是用较大的数除以较小的数,
然后用较小的数去除余数,再用新的余数去除小的数,如此反复,
直到余数为零为止,此时除数就是最大公约数。具体步骤如下:
*/
int Common_divisor_max(int x, int y){
    int max = max_min(x,y,1);   //求出最大数
    int c_n = x+y-max;  //除数
    int c = max % c_n;    //被除数
    while(c != 0){
        int di = c; //除数被除数交换
        c = c_n;
        c_n = di;
        c = c % c_n;
    }
    return c_n;
    /*
    for(int i = max;i >= 1;i--){
        if(x%i == 0 && y%i == 0){   //满足最大公约数
            return i;
        }
    }
    */
    //return 0;
}


//求出最小公倍数
int Common_multiple_min(int x,int y,int yue){

    return x*y/yue;

    /*
    int max = max_min(x,y,1);   //求出最大数
    for(int i = max; i<= x*y;i = i + yue){
        if(i%x == 0 && i%y == 0){
            return i;
        }
    }
    */
    //return -1;  //错误
}



int main (){
    int x,y;
    scanf("%d %d",&x, &y);
    int P,Q;

    P = max_min(x,y, 0);
    Q = max_min(x,y, 1);
    
    int cnt = 0;    //计数满足要求的Q P
    for(int i = P; i <= Q; i = i + x){
        //遍历方式求解,时间复杂度太高
        for(int j = Q; j >= P; j= j - x){
            if(j*i == x*y){
                int yue = Common_divisor_max(i, j);
                if(yue != x)   ;//跳过
                else if(Common_multiple_min(i,j, yue) == y){
                    cnt++;
                    //printf("P = %d   Q = %d \r\n", i,j);
                }
            }
            
        }
    }
    
    printf("%d\r\n",cnt);
    return 0;
}   

总结:

        这个程序的主要功能是寻找满足条件的数对 P 和 Q,使得它们的乘积等于输入的 x 和 y 的乘积。程序的思路是在 P 和 Q 的所有可能组合中进行遍历,找到满足条件的数对并计数。

不足之处:

  1. 时间复杂度高:程序的时间复杂度较高,主要是由于双层嵌套的循环造成的。这使得程序在处理大量数据时的计算成本较高,需要较长的运行时间。

  2. 重复计算:程序在遍历所有可能的 P 和 Q 组合时,没有避免重复计算。这意味着某些计算可能会被多次执行,浪费了计算资源。

  3. 输出不必要信息:程序在找到满足条件的数对 P 和 Q 时,会输出它们的值。这可能会导致输出大量不必要的信息,影响程序的可读性。

改进意见:

  1. 优化算法:可以通过数学推导和优化算法来降低程序的时间复杂度。例如,可以使用辗转相除法来计算最大公约数,使用最小公倍数的性质来避免重复计算等。

  2. 避免重复计算:可以使用缓存等技术来避免重复计算。例如,可以将已经计算过的结果存储在一个哈希表中,避免重复执行相同的计算。

  3. 简化输出:可以通过修改程序的输出方式来简化输出内容。例如,可以只输出满足条件的数对的数量,而不是输出每个满足条件的数对的值。

  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0X78

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值