简单数学问题

整理下《算法笔记》,方便查看。

一、最大公约数&最小公倍数

欧几里得定理:设a,b均为正整数,那么gcd(a,b)=gcd(b,a%b)。

a<b,定理就先交换a和b。

注意:0和任意正整数a的gcd是a。

//最大公约数
int gcd(int a,int b)
{
    return !b ? a : gcd(b,a % b);
}

设最大公约数为res,最小公倍数lcm即为\frac{a}{res}*b

二、分数

PAT甲1088是比较经典的分数处理问题,求2个分数的和、差、积、商,输出最简形式。

题目链接

表示、化简、运算、输出,代码阐释得很清楚。

#include 
#include 

using namespace std;

typedef long long ll;

ll gcd(ll a,ll b)
{
        return !b ? a : gcd(b,a % b);
}

struct Fraction{
        ll nume,deno;
};

Fraction reduction(Fraction a)
{
        if(a.deno < 0)
        {
                a.deno = -a.deno;
                a.nume = -a.nume;
        }
        if(a.nume == 0)
        {
                a.deno = 1;
        }
        else
        {
               int d = gcd(abs(a.nume),abs(a.deno));
               a.nume /= d;
               a.deno /= d;
        }
        return a;
}

Fraction add(Fraction a,Fraction b)
{
        Fraction res;
        res.deno = a.deno * b.deno;
        res.nume = a.deno * b.nume + a.nume * b.deno;
        return reduction(res);
}

Fraction sub(Fraction a,Fraction b)
{
        Fraction res;
        res.deno = a.deno * b.deno;
        res.nume = a.nume * b.deno - a.deno * b.nume;
        return reduction(res);
}

Fraction times(Fraction a,Fraction b)
{
        Fraction res;
        res.deno = a.deno * b.deno;
        res.nume = a.nume * b.nume;
        return reduction(res);
}

Fraction divide(Fraction a,Fraction b)
{
        Fraction res;
        res.deno = a.deno * b.nume;
        res.nume = a.nume * b.deno;
        return reduction(res);
}

void showFrac(Fraction a)
{
        a = reduction(a);
        if(a.nume < 0)
        {
                printf("(");
        }
        if(a.deno == 1)
        {
                printf("%lld",a.nume);
        }
        else if(abs(a.nume) > abs(a.deno))
        {
                printf("%lld %lld/%lld",a.nume / a.deno,abs(a.nume) % a.deno,a.deno);
        }
        else
        {
                printf("%lld/%lld",a.nume,a.deno);
        }
        if(a.nume < 0)
        {
                printf(")");
        }
}

int main()
{
        Fraction a,b;
        scanf("%lld/%lld%lld/%lld",&a.nume,&a.deno,&b.nume,&b.deno);

        showFrac(a);
        printf(" + ");
        showFrac(b);
        printf(" = ");
        showFrac(add(a,b));
        printf("\n");

        showFrac(a);
        printf(" - ");
        showFrac(b);
        printf(" = ");
        showFrac(sub(a,b));
        printf("\n");

        showFrac(a);
        printf(" * ");
        showFrac(b);
        printf(" = ");
        showFrac(times(a,b));
        printf("\n");

        showFrac(a);
        printf(" / ");
        showFrac(b);
        printf(" = ");
        if(b.nume == 0)
        {
                printf("Inf\n");
        }
        else
        {
                showFrac(divide(a,b));
                printf("\n");
        }

        return 0;
}

三、素数

1、判断素数

bool isPrime(int a)
{
        if(a <= 1)   //1不是素数,也不是合数
                return false;
        int tmp = (int)sqrt(1.0 * a);
        for(int i = 2;i <= tmp;i++)
        {
                if(a % i == 0)
                        return false;
        }
        return true;
}

2、打素数表

第一种方法是枚举判断,复杂度O(n\sqrt{n})

const int maxn = 10010;
int prime[maxn],num = 0;

void Prime_table()
{
        for(int i = 2;i < maxn;i++)
        {
                if(isPrime(i))
                {
                        prime[num++] = i;
                }
        }
}

第二种是Eratosthenes筛法,复杂度O(nlog(logn)),比枚举更优,代码更短。

const int maxn = 10010;
int prime[maxn],num = 0;
bool p[maxn] = {false};  //i为素数,p[i]为false

void Prime_table()
{
        for(int i = 2;i < maxn;i++)
        {
                if(p[i] == false)
                {
                        prime[num++] = i;
                        for(int j = i + i;j < maxn;j += i)
                        {
                                p[j] = true;
                        }
                }
        }
}

3、分解质因子

如果n存在[2,n)范围内的质因子,要么质因子全部\leq \sqrt{n},要么只有一个> \sqrt{n}的质因子,其余都\leq \sqrt{n}

注意:1要特判。

//存储
struct factor{
        int x,cnt; //x为质因子,cnt为该质因子个数
}fac[20];

int num = 0;  //记录不同因子个数
//枚举小于等于sqrt(n)内的所有质因子,判断哪个是n的因子
for(int i = 0;prime[i] <= sqrt(n);i++)
{
        if(n % prime[i] == 0)
        {
                fac[num].x = prime[i];
                fac[num].cnt = 0;
                while(n % prime[i] == 0)
                {
                        fac[num].cnt++;
                        n /= primep[i];
                }
                num++;
        }
}

//如果n仍然大于1,说明n有一个大于sqrt(n)的质因子
if(n != 1)
{
        fac[num].x = n;
        fac[num++].cnt = 1;
}

 

你可能感兴趣的:(算法)