编代码遇到的问题-1

题目是CP1201
第一次代码是

 #include <stdio.h>
 #include <stdlib.h>
 int main()
{
    int a=0,m,n,i;
    scanf("%d,%d",&m,&n);
    if((m+1)%i==0&&(n+1)%i==0&&i<m+1&&i<n+1)
    {
        a=i;
    }
    printf("%d\n",a);
    return 0;
} 

我以为能把符合那四个条件的数赋给变量a,但事实是if意味着只有系统随机给i生成的数满足那四个条件时才会把值赋给a,所以这么写是不对的。
应改为

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int a=0,m,n,i;
    scanf("%d%d",&m,&n);
    do
    {
        if(m<=-1||n<=-1)
        {
            printf("Please input again.");
            scanf("%d,%d",&m,&n);//对变量m和n重新读入数据的方式就是再把读入语句写一遍,用新数据覆盖老数据。
        }
    }
    while(m<=-1||n<=-1);
    m+=1;
    n+=1;
    int min=(m<n)?m:n;
    for(i=1;i<=min; i++)
    {
        if(m%i==0&&n%i==0)
        {
            a=i;
        }
    }
    printf("%d\n",a);
    return 0;
}

其中增加了一个对输入的数据必须是正整数的限制,这种限制方法还可以这样

  • 如果只判断一次
#include <stdio.h>

int main()
{
    int m, n;
    printf("请输入m和n的值:");
    if (scanf("%d %d", &m, &n) != 2 || m <= 0 || n <= 0)
    {
        printf("输入的m和n必须是正整数!\n");
    }
    else
    {
        printf("输入的m和n分别是:%d 和 %d\n", m, n);
    }
    return 0;
}

若判断多次知道输入的类型正确为止,要用循环,因为如果仅仅在if语句后的printf("输入的m和n必须是正整数!\n");后加一个scanf("%d %d", &m, &n);,同样只能重输一次,所以要用循环。如下:

#include <stdio.h>

int main() {
    int m, n;
    do {
        printf("请输入m和n的值:");
        if (scanf("%d %d", &m, &n) != 2 || m <= 0 || n <= 0) {
            printf("输入的m和n必须是正整数!\n");
        } else {
            printf("输入的m和n分别是:%d 和 %d\n", m, n);
            break; // 输入符合要求时退出循环
        }
    } while (1); // 一直循环直至输入符合要求
    return 0;
}

要实现当输入的m和n不符合要求时就继续输入直至符合要求为止,你可以使用一个循环来实现这个功能。可以使用do-while循环,这样可以先执行一次输入和判断,然后根据判断结果决定是否继续循环。在这个修改后的代码中,使用了do-while循环来实现当输入的m和n不符合要求时就继续输入直至符合要求为止。

在C语言中,while循环的条件部分需要是一个表达式,只有在表达式的值为真(非零)时才会执行循环体。因此,通常我们会使用一个逻辑表达式作为while循环的条件,例如i < 10或者x != 0等等。
在我之前给出的代码中,我使用了while(1)来表示一个无限循环。这是因为条件部分需要一个逻辑表达式,而1在C语言中被视为真。因此,while(1)表示条件永远为真,因此循环会一直执行下去,直到遇到break语句或者其他方式退出循环。
所以,在这个例子中,while(1)的作用是创建一个无限循环,直到输入的m和n符合要求时才会通过break语句退出循环。

求最大公约数时除了上面的正确代码,还可以把for循环处改为

for(i=min;i>=1; i--)
    {
        if(m%i==0&&n%i==0)
        {
            a=i;
            break;
        }
    }
如果求最小公约数,可改为

for(i=min;i>=1; i--)
{
if(m%i0&&n%i0)
{
a=i;
}
}

for(i=1;i<=min; i++)
{
if(m%i0&&n%i0)
{
a=i;
break;
}
}

如果想求除了1以外的最小公约数,把两种代码里for后的括号里关系表达式里的等号去掉就行了。
且娄老师讲过求两个正整数的最大公约数可以用辗转相除法。
> 辗转相除法, 又名欧几里德算法(Euclidean algorithm),是求两个正整数之最大公约数的算法。它是已知最古老的算法, 其可追溯至公元前300年前。

> 它的具体做法是:用较大数除以较小数,再用出现的余数(第一余数)去除除数,再用出现的余数(第二余数)去除第一余数,如此反复,直到最后余数是0为止。如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数。 

> 另一种求两数的最大公约数的方法是更相减损法。
> 例如:a=25,b=15,a%b=10,b%10=5,10%5=0,最后一个为被除数余数的除数就是5,5就是所求最大公约数。

> 自然语言描述
用辗转相除法确定两个正整数 a 和 b(a≥b) 的最大公因数gcd(a,b):

> 当a mod b=0 时gcd(a,b)=b,否则
gcd(a,b) = gcd(b,a mod b)
递归或循环运算得出结果

> 伪代码
这个算法可以用递归写成如下:
gcd 简易函数
c语言辗转相除代码:
C++语言实现

int gcd(int a, int b)

{

if(b==0) return a;

return gcd(b,a%b);

}

> C语言实现

int gcd(int a,int b)

{

return a%b?gcd(b,a%b):b;

}

所以这道题还可以用辗转相除法做。
posted @ 2023-12-08 11:45  20231408徐钰涵  阅读(5)  评论(0编辑  收藏  举报