一些常见数学问题的算法

代码来源:晴神《算法笔记》!!

一. 最大公约数

int gcd(int a, int b){
	if(b == 0) return a;
	else return gcd(b, a%b);
}

二. 最小公倍数

lcm(a, b) = ab / d,ab有可能溢出,因此更恰当的写法是a/d*b。

三. 分数的四则运算

分数的表示
struct fraction{
	int up, down;
};
分数的化简
fraction reduction(fraction a){
	if(a.down < 0){
		a.up = -a.up;
		a.down = -a.down;
	}
	if(a.up == 0)
		a.down = 1;
	else{
		int d = gcd(abs(a.up), abs(a.down));
		a.up /= d;
		a.down /= d;
	}
	return a;
}
分数的加法
fraction add(fraction a, fraction b){
	fraction res;
	res.up = a.up*b.down + a.down*b.up;
	res.down = a.down*b.down;
	return reduction(res); 
}

减、乘、除类似,除法需判断除数是否为0,略

分数的输出
void showres(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);
}

一般情况下,计算过程中,分子或者分母有可能超出int范围,因此最好用long long存储。

四. 素数

判断是否是素数
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 = 101;
int prime[maxn], pnum = 0;
bool p[maxn] = {0};
void find_prime(){
	for(int i = 2; i < maxn; i++){
		if(p[i] == false){
			prime[pnum++] = i;
			for(int j = i + i; j < maxn; j+=i){
				p[j] = true;
			}
		} 
	}
}

五. 质因子分解

对于一个正整数n来说,如果它存在[2,n]范围内的质因子,要么这些质因子全部小于等于sqrt(n),要么只存在一个大于sqrt(n)的质因子,而其余质因子全部小于等于sqrt(n)。

struct factor{
	int x, cnt;
}fac[10];   //只需要开到10即可

//在1-sqrt(n)范围内 
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;
}

//如果结束后n仍大于1
if(n != 1){
	fac[num].x = n;
	fac[num++].cnt = 1;
} 

六. 大整数运算

存储
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 - 1 - i] - '0';  //记得要-'0' 
	}
	return a;
} 
比较大小
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;	 
	}
}
高精度加法
//适用于两个对象都为非负整数
//如果有一方为负,转换为高精度减法;如果都是负的,负号提取 
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[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];
	}
	//去掉高位多余的0,但也要保证至少有一位 
	while(c.len - 1 >= 1 && c.d[len-1] == 0){
		c.len--;
	}
	return c;
}
高精度与低精度的乘法
//如果有负数,先记录下负号,把绝对值代入 
bign mul(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 devide(bign a, int b, int &r){       //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[len-1] == 0){
		c.len--;
	}
	return c;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值