算法笔记 第5章 入门篇(3) --数学问题 学习笔记

5.1 简单数学

PAT A1069/B1019 The Black Hole of Numbers (20分)

For any 4-digit integer except the ones with all the digits being the same, if we sort the digits in non-increasing order first, and then in non-decreasing order, a new number can be obtained by taking the second number from the first one. Repeat in this manner we will soon end up at the number 6174 -- the black hole of 4-digit numbers. This number is named Kaprekar Constant.

For example, start from 6767, we'll get:

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
7641 - 1467 = 6174
... ...

Given any 4-digit number, you are supposed to illustrate the way it gets into the black hole.

Input Specification:

Each input file contains one test case which gives a positive integer N in the range (.

Output Specification:

If all the 4 digits of N are the same, print in one line the equation N - N = 0000. Else print each step of calculation in a line until 6174 comes out as the difference. All the numbers must be printed as 4-digit numbers.

Sample Input 1:

6767

Sample Output 1:

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174

Sample Input 2:

2222

Sample Output 2:

2222 - 2222 = 0000
#include<cstdio>
#include<algorithm>
using namespace std;
bool cmp(int a,int b){
    return a > b;
}
void toarray(int n,int num[]){
    for(int i=0;i<4;i++){
        num[i] = n%10;
        n /= 10;
    }
}
int tonumber(int num[]){
    int sum = 0;
    for(int i=0;i<4;i++){
        sum = sum*10 + num[i];
    }
    return sum;
} 
int main(){
    int n;
    scanf("%d",&n);
    int num[5];
    while(1){
        int max1,min1;
        toarray(n,num);
        sort(num,num+4);
        min1 = tonumber(num);
        sort(num,num+4,cmp);
        max1 = tonumber(num);
        n = max1 - min1;
        printf("%04d - %04d = %04d\n",max1,min1,n);
        if(n==6174 || n==0){
            break;
        }
    }
    return 0;
}

5.2 最大公约数与最小公倍数

5.2.1 最大公约数

1818: 最大公约数

题目描述

输入两个正整数,求其最大公约数。

输入

测试数据有多组,每组输入两个正整数。

输出

对于每组输入,请输出其最大公约数。

样例输入

49 14

样例输出

7
#include<cstdio>
int gcd(int a,int b){
    if(b == 0)
         return a;
    else 
        return gcd(b,a%b);
}
int main(){
    int m,n;
    while(scanf("%d%d",&m,&n)!=EOF){
        printf("%d\n",gcd(m,n));
    }
    return 0;
}

 

5.3 分数的四则运算

5.3.1 分数的表示和化简

1.分数的表示

struct Fraction{

  int up,down;

};

规定:

①使down为非负数。如果分数为负,那么令分子up为负即可。

②如果该分数恰为0,那么规定其分子为0,分母为1.

③分子和分母没有除了1以外的公约数。

2.分数的化简

Fraction reduction(Fraction result){
    if(result.down < 0){
        result.up = -result.up;
        result.down = - result.down;
    }
    if(result.up == 0){
        result.down = 1;
    }else{
        int d = gcd(abs(result.up),abs(result.down));
        result.up /= d;
        result.down /= d;
    }
    return result;
}

5.3.2 分数的四则运算

1.分数的加法

Fraction add(Fraction f1,Fraction f2){
    Fraction result;
    result.up = f1.up * f2.down + f2.up*f1.down;
    result.down = f1.down * f2.down;
    return reduction(result);
}

2.分数的减法

Fraction minu(Fraction f1,Fraction f2){
    Fraction result;
    result.up = f1.up * f2.down - f2.up*f1.down;
    result.down = f1.down * f2.down;
    return reduction(result);
}

3.分数的乘法

Fraction multi(Fraction f1,Fraction f2){
    Fraction result;
    result.up = f1.up * f2.up;
    result.down = f1.down * f2.down;
    return reduction(result);
}

4.分数的除法

Fraction divide(Fraction f1,Fraction f2){
    Fraction result;
    result.up = f1.up * f2.down;
    result.down = f1.down * f2.up;
    return reduction(result);
}

只有当除数不为0时,才能用上面的函数进行计算。

5.3.3 分数的输出

void showResult(Fraction r){
    r = reduction(r);
    if(r.down == 1){
        printf("%lld",r.up);
    }else if(abs(r.up) > r.down){
        printf("%d %d/%d",r.up/r.down,abs(r.up) % r.down,r.down);
    }else{
        printf("%d/%d",r.up,r.down);
    }
}

5.4 素数

素数又称为质数,是指除了1和本身之外,不能被其他数整除的一类数。1既不是素数,也不是合数。

5.4.1 素数的判断

bool isPrime(int n){
    if(n <= 1)
        return false;
    int sqr = (int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++){
        if(n % i == 0)
            return false;
    }
    return true;
}
 sqrt的作用为一个浮点数开根号,需要添加math.h头文件。

5.4.2 素数表的获取
const int maxn = 101; //表长 
int prime[maxn],pNum = 0; //prime数组存放所有素数,pNum为素数个数 
bool p[maxn] = {0}; //p[i] == true表示i是素数 
void Find_Prime(){
    for(int i=1;i<maxn;i++){
        if(isPrime(i) == true){
            prime[pNum++] = i;
            p[i] = true;
        }
    }
}

埃氏筛法:

例子:求1~15中的所有素数

 

 PAT B1013 数素数 (20分)

令 Pi​​ 表示第 i 个素数。现任给两个正整数 MN104​​,请输出 PM​​ 到 PN​​ 的所有素数。

输入格式:

输入在一行中给出 M 和 N,其间以空格分隔。

输出格式:

输出从 PM​​ 到 PN​​ 的所有素数,每 10 个数字占 1 行,其间以空格分隔,但行末不得有多余空格。

输入样例:

5 27

输出样例:

11 13 17 19 23 29 31 37 41 43
47 53 59 61 67 71 73 79 83 89
97 101 103
#include<cstdio>
#include<cmath>
const int maxn = 10010;
long long prime[maxn];
bool isPrime(int a){
    for(int i=2;i<=sqrt(a);i++){
        if(a % i == 0){
            return false;
        }
    }
    return true;
} 
int main(){
    int m,n;
    scanf("%d%d",&m,&n);
    int num = 1;
    for(int i=2;num<=n;i++){
        if(isPrime(i)==true){
            prime[num++] = i;
        }
    }    
    int count=0;
    for(int i=m;i<=n;i++){
        printf("%d",prime[i]);
        count++;
        if(count %10!=0 && i<n)
            printf(" ");
        else
            printf("\n");
    }
    return 0;
}

 5.5 质因子分解

所谓质因子分解是指将一个正整数n写成一个或多个质数的乘积形式,例如6 = 2 * 3,8 = 2 * 2 * 2,180 = 2 * 2 * 3 *3 *5。

定义结构体factor,用来存放质因子及其个数,如下所示:

struct factor{

  int x,cnt;

}fac[10];

例如对180来说,fac数组如下:fac[0].x = 2; fac[0].cnt = 2;  fac[1].x = 3; fac[1].cnt = 2;   fac[2].x = 5;fac[2].cnt = 1;

PAT A1059 Prime Factors (25分)

Given any positive integer N, you are supposed to find all of its prime factors, and write them in the format N = p1​​k1​​​​×p2​​k2​​​​××pm​​km​​​​.

Input Specification:

Each input file contains one test case which gives a positive integer N in the range of long int.

Output Specification:

Factor N in the format = p1​​^k1​​*p2​​^k2​​**pm​​^km​​, where pi​​'s are prime factors of N in increasing order, and the exponent ki​​ is the number of pi​​ -- hence when there is only one pi​​, ki​​ is 1 and must NOT be printed out.

Sample Input:

97532468

Sample Output:

97532468=2^2*11*17*101*1291
#include<cstdio>
#include<cmath>
bool isprime(int n){
    if(n<=1){
        return false;
    }
    int sqr = (int)sqrt(1.0*n);
    for(int i=2;i<=sqr;i++){
        if(n%i == 0)
            return false;
    }
    return true;
}
const int maxn = 100010;
int prime[maxn],pNum=0;
void Find_Prime(){
    for(int i=1;i<maxn;i++){
        if(isprime(i)){
            prime[pNum++] = i;
        }
    }
}
struct factor{
    int x;
    int cnt; 
}fac[10];
int main(){
    Find_Prime();
    int n,num=0;
    scanf("%d",&n);
    if(n==1){
        printf("1=1\n");
    }else{
        printf("%d=",n);
        int sqr = (int)sqrt(n*1.0);
        for(int i=0;i<pNum && prime[i]<=sqr;i++){
            if(n % prime[i]==0){
                fac[num].x = prime[i];
                fac[num].cnt = 0;
                while(n%prime[i]==0){
                    fac[num].cnt++;
                    n /= prime[i];
                }
                num++;
                if(n == 1)
                    break;
            }
        }
        if(n != 1){
            fac[num].x = n;
            fac[num++].cnt = 1;
        }
    }
    for(int i=0;i<num;i++){
        if(i > 0)
            printf("*");
        printf("%d",fac[i].x);
        if(fac[i].cnt>1)
            printf("^%d",fac[i].cnt);
    }
    return 0;
}

5.6 大整数运算

5.6.1 大整数的存储

使用数组存储大整数即可,例如定义int型数组d[1000],那么这个数组中的每一位就代表了存放的整数的每一位。如将整数235813存储到数组中,

则有d[0]=3, d[1]=1, d[2]=8, d[3]=5 ,d[4]=3, d[5]=2,即整数的高位存储在数组的高位,整数的低位存储在数组的低位。但是把整数按字符串%s读入的时候,实际上是逆味存储的,即str[0] = ‘2',

str[1] = '3' ...,因此在读入之后需要在另存为至d[]数组的时候反转一下。

会定义一个int型变量len来记录长度,并和d数组组合成结构体。

struct bign{

  int d[1000];

  int len;

  bign(){

    memset(d,0,sizeof(d));

    len = 0;

  }

};

将字符串转换为bign结构体

bign change(char str[]){
    bign a;
    a.len = strlen(str);
    for(int i=0;i<a.len;i++){
        a.d[i] = str[a.len - i -1] - '0';
    }
    return a;
}

比较两个bign变量的大小

int compare(bign a,bign b){
    if(a.len > b.len)
        return 1;
    else if(a.len < b.len)
        return -1;
    else{
        for(int i = a.len - 1;i>=0;i--){
            if(a.d[i] > b.d[i])
                return 1;
            else if(a.d[i] < b.d[i])
                return -1;
        }
        return 0;
    }
}

5.6.2 大整数的四则运算

bign add(bign a,bign b){
    bign c;
    int carry = 0;
    for(int i=0;i<a.len || i<b.len;i++){
        int temp = a.d[i] + b.d[i] + carry;
        c.d[c.len++] = temp % 10;
        carry = temp / 10;
    }
    if(carry != 0){
        c.d[c.len++] = carry;
    } 
    return c;
}
bign sub(bign a,bign b){
    bign c;
    for(int i=0;i<a.len || i<b.len;i++){
        if(a.d[i] < b.d[i]){
            a.d[i+1]--;
            a.d[i] += 10;
        }
        c.d[c.len++] = a.d[i] - b.d[i];
    }
    while(c.len - 1>=1 && c.d[c.len - 1]==0){
        c.len--;
    }
    return c;
}
bign multi(bign a,int b){
    bign c;
    int carry = 0;
    for(int i=0;i<a.len;i++){
        int temp = a.d[i]*b + carry;
        c.d[c.len++] = temp%10;
        carry = temp/10;
    }    
    while(carry != 0){
        c.d[c.len++] = carry % 10;
        carry /= 10;
    }
    return c;
}
bign divide(bign a,int b,int &r){
    bign c;
    c.len = a.len;
    for(int i=a.len - 1;i>=0;i--){
        r = r*10+ a.d[i];
        if(r < b)
            c.d[i] = 0;
        else{
            c.d[i] = r/b;
            r = r%b;
        }
    }
    while(c.len - 1>=1 && c.d[c.len - 1] == 0){
        c.len--;
    } 
    return c;
}

5.7 扩展欧几里得算法

 

 
posted @ 2020-01-31 16:59  程序员小应  阅读(171)  评论(0编辑  收藏  举报