美文网首页
PTA刷题总结-Part 2 模拟与数学问题

PTA刷题总结-Part 2 模拟与数学问题

作者: 苏wisdom | 来源:发表于2020-03-12 13:09 被阅读0次

PTA刷题总结-Part 1 基础部分
PTA刷题总结-Part 2 模拟与数学问题
PTA刷题总结-Part 3 数据结构与算法

2 数学问题和基本模拟

2.1 计算闰年

闰年的判别条件是该年年份能被4整除但不能被100整除、或者能被400整除。闰年的2月有29天。

计算闰年真的是个非常常见的题目了,其实只要明白了闰年计算方法,剩下的就是条件语句中的逻辑问题。(题目:7-19 计算天数 (15分))

#include <stdio.h>


int main() {
    int daysOfM[] = {31,28,31,30,31,30,31,31,30,31,30,31};
    int daysOfMR[] = {31,29,31,30,31,30,31,31,30,31,30,31};
    int yyyy,mm,dd=0;
    int result = 0;
    scanf("%d/%d/%d",&yyyy,&mm,&dd);
    int isRun = 0;
    if ((yyyy%4==0 && yyyy%100!=0)|| yyyy%400==0 ){
        isRun = 1;
    } 
    
    for (int i=1; i<mm;i++) {
        if (i!=2 || i==2 && isRun==0) {
            result += daysOfM[i-1];
        } else {
            result += daysOfMR[i-1];
        }
    }
    result += dd;
    printf("%d\n",result);
    return 0;
}

2.2 最大公约数GCD和最小公倍数LCM

  • 最大公约数(Greatest Common Divisor)一般使用辗转相除法
  • 最小公倍数( Least Common Multiple )等于a*b/两数最大公约数,但是我们一般写成a/gcd*b,先除后乘,避免a*b的结果太大导致溢出

题目:7-26 最大公约数和最小公倍数 (15分)

#include <stdio.h>

int main() {
    int m,n = 0;
    scanf("%d %d",&m, &n);
    
    int m1 = m;
    int n1 = n;
    while (n1!=0){
        int temp = m1%n1;
        m1 = n1;
        n1 = temp;
    }
    // m1 是最大公倍数
    int lcm = m/m1*n;
    printf("%d %d\n",m1,lcm); 
    
    return 0;
}

题目:7-112 约分最简分式 (15分)

#include <stdio.h>
int gcd(int a,int b){
    while (b!=0){
        int temp = a%b;
        a = b;
        b = temp;
    }
    return a;
}

int main() {
    int up = 0;
    int down = 0;
    scanf("%d/%d", &up,&down);
    int g = gcd(up,down);
    up = up/g;
    down = down/g;
    printf("%d/%d", up, down);
    return 0;
}

2.3 取出整数的各位数字

常见的题目类型有从右向左取(从个位开始)和从左向右取(从最高位开始)的。

无所谓顺序的,比如求各位数字的和(题目:7-28 求整数的位数及各位数字之和 (15分)),就可以直接从右向左取。不断地对10求余,取出来,然后对原数除以10,去掉末位。一直到原数最后只剩下一位。
注意,下面代码中之所以使用do{...}while()而不使用while(){},是为了保证输入数字0的时候,也能计算出来有1位。

#include <stdio.h>

int main() {
    int m=0;
    scanf("%d",&m);
    
    int count = 0;
    int sum = 0;
    do{
        int digit = m %10;
        m = m/10;
        count++;
        sum+=digit;
    }while (m >0);
    printf("%d %d\n", count, sum);
    return 0;
}

题目:7-100 逆序的三位数 (10分)

#include <stdio.h>

int main() {
    int x = 0;
    scanf("%d", &x);
    int r = 0;
    do {
        int digit  = x%10;
        r = r*10+digit;
        x /= 10;
    } while(x>0);
    
    printf("%d\n", r);
    return 0;
}

但是有的题目要求你从高位开始输出,不得不从左向右取,目前看有两种方法

  • 先找到最高位,比如42345的最高位是是42345/10000=4,然后次高位用2345/1000=2,以此类推。
  • 如果题目已经告诉你输入的整数位数范围,可以使用定长的字符数组
    题目:7-37 输出整数各位数字 (15分)
#include <stdio.h>
long count(long m); 
int main() {
    long m = 0;
    scanf("%ld",&m);
    long c =  count(m);
    while (c != 0){
        int digit =  m / c;
        printf("%d",digit);
        if (c >= 9){
            printf(" ");
        }
        m = m % c;
        c = c/10;
        
    }

    return 0;
}

long count(long m){
    long c = 1;
    while(m>9) {
        m = m/10;
        c = c*10;
    }
    return c;
}

题目:7-30 念数字 (15分)

#include <stdio.h>
#include <string.h>
int main() {
    char str[1000] = {'\0'};
    scanf("%s", str);
    int len = strlen(str);
    for (int i=0; i< len; i++) {
        switch(str[i]){
            case '-':printf("fu");break;
            case '0':printf("ling");break;
            case '1':printf("yi");break;
            case '2':printf("er");break;
            case '3':printf("san");break;
            case '4':printf("si");break;
            case '5':printf("wu");break;
            case '6':printf("liu");break;
            case '7':printf("qi");break;
            case '8':printf("ba");break;
            case '9':printf("jiu");break;
            default:break;
        }
        if (i<len-1) {
            printf(" ");
        }
    }
    
    return 0;
}

2.4 素数

素数就是我们说的质数,是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。1不是素数,2是素数。

题目:7-33 统计素数并求和 (20分)

#include <stdio.h>
#include <math.h>

int isPrime(int k);
int main() {
    int m,n = 0;
    scanf("%d %d",&m,&n);
    int count = 0;
    int sum = 0;
    for (int i=m; i<=n;i++){
        if (isPrime(i)){
            count++;
            sum+=i;
        }
    }
    
    printf("%d %d\n", count,sum);

    return 0;
}

int isPrime(int k){
    int isP = 1;
    if (k < 2){
        isP = 0;
        return isP;
    } else {
        for(int i=2; i<sqrt(k);i++){
            if (k % i==0){
                isP = 0;
                break;
            }
        }
    }
    return isP;
}

这道题中如果最小值已知是从1开始计算的话,可以考虑使用素数表的方法去实现isPrime(),而不是sqrt(k) ,如下,构造了一个小于m的素数表。

#include <stdio.h>
int prime[20000] = {2};

int isPrime(int x, int prime[], int count){
    int r = 1;
    for (int i=0;i<count;i++){
        if (x % prime[i] == 0){
            r = 0;
            break;
        }
    }
    return r;
}
int main() {
    int m=0;
    scanf("%d", &m);
    int count = 1;
    for (int i=3;i<m;i++){
        if (isPrime(i, prime,count)){
            prime[count++] = i;
        }   
    }
    return 0;
}

但是经过实际题目检验,发现当N非常大,接近于10^5 时,使用prime数组方式判断是否是素数的方法面临超时风险,而使用sqrt不会
题目:素数对猜想 (20分)

#include <stdio.h>
#include <math.h>
int r = 0; 
int isPrime(int k){
    int r = 1;
    for (int i=2;i<=sqrt(k);i++){
        if (k % i==0){
            r = 0;
        }
    }
    return r;
}
int main(){
    int n = 0;
    scanf("%d", &n);
    int count = 1;
    int pre = 2;
    for (int i=3;i<=n;i++){
        if (isPrime(i)){
            if (i-pre==2){
                r++;
            }
            count ++;
            pre = i;
        }
    }
    
    

    printf("%d", r);
    return(0);
}

2.5 使用数组进行循环模拟

题目:猴子选大王
典型的约瑟夫环问题,这里可以使用数组进行模拟。

#include <stdio.h>
int a[1001];// 1表示淘汰 
int main(){
    int n = 0,s=0,count=0;
    int i = 0; // 数组下标 
    scanf("%d", &n);
    while(s != n-1){ // 淘汰猴子的数量达到n-1时退出
        i++;
        if (i>n){
            i = 1;
        }
        if(a[i] == 0){ // 只判断剩下的猴子 
            count++;
            if (count %3==0){
                a[i] = 1;
                s++; // 每次淘汰一只猴子,直到s==n-1,剩下最后一只 
            } 
        } 
        
    }
    for (int j=1;j<=n;j++){
        if (a[j]==0){
            printf("%d",j);
        }
    }
    return(0);
}

其他解法单独写了一章,可见PTA例题精析-约瑟夫问题 Josephus Problem

题目:7-39 天梯赛座位分配 (20分)
三维数组,纵向循环

#include <stdio.h>
int teamNum[101];
int a[101][11][11]; // i,j,k
int main(){
    int n = 0,maxTeamNum = 0;
    scanf("%d", &n);
    for (int i=1;i<=n;i++){
        scanf("%d", &teamNum[i]);
        if (teamNum[i] >maxTeamNum){
            maxTeamNum = teamNum[i];
        }
    }
    int num = 0,lastI = 0;
    while (maxTeamNum>0){
        for (int k=1;k<=10;k++){
            for (int i=1;i<=n;i++){
                int j=1;
                while (a[i][j][10]>0 && j<=teamNum[i]){
                    j++;
                }
                if (j<=teamNum[i]){
                    if (lastI == i){
                        num +=2;
                    } else {
                        num++;
                    }
                    a[i][j][k] = num;
                    lastI = i;
                }
            }
        }
        maxTeamNum--;
    }

    // output
    for (int i=1;i<=n;i++){
        printf("#%d\n", i);
        for (int j=1;j<=teamNum[i];j++){
            printf("%d", a[i][j][1]);
            for (int k=2;k<=10;k++){
                printf(" %d", a[i][j][k]);
            }
            printf("\n");
        }
    }
    return 0;
}

相关文章

网友评论

      本文标题:PTA刷题总结-Part 2 模拟与数学问题

      本文链接:https://www.haomeiwen.com/subject/uidujhtx.html