最大公约数(GCD)

本篇博客主要介绍最大公约数及其求解方法。

最大公约数

  首先,最大公约数是什么?
  按照定义,最大公约数是两个数的公共因子中最大的一个。所以两个数最大公因数一定是确定的,同时最大公因数只能对于两个以上的数存在。

求解

1.枚举因数

  按照定义,我们可以知道,两个数的最大公因数一定是这两个数的公因数,所以很容易想到,当我们将每一个公因子求出来时,其中的最大因子一定是最大公因数。
  由此可以得到一个朴素算法:对于 n n n, m m m两个数,枚举小于等于 n \sqrt{n} n ​的每一个数,当这个数是 n n n的因子时,判断这个数是不是 m m m的因子,如果是,那么记录该数,并判断它是否是已经找到的数中的最大值。
  当然,可以选择性地只枚举小于等于 min ⁡ ( n , m ) \sqrt{\min(n , m)} min(n,m) ​的数,但是实际优化程度不大,仅在 n , m n , m n,m相差较大时才有明显效果。

int gcd(int n, int m)
{
	int maxn = 1;
	for(int i=2; i<sqrt(n)/*sqrt(min(n , m))*/; i++)
	{
		if(n%i==0)
		{
			if(m%i==0)
			{
				if(maxn < i)
					maxn = i;
			}
		}
	}
	return maxn;
}
2.构造

  上述方法明显多扫描了许多数字,所以我们可以考虑构造最大公因数。
  既然最大公因数是两数的最大的公因数,那么最大公因数一定包含两数所有的公共质因子,所以我们可以先将这两个数分解质因子再用质因子构造最大公因数。

int f[Size], q[Size] , qn[Size][Size][2], tot[Size];
int top = 0;

void make_q(int n)
{
    for(int i = 2 ; i <= n ; i++)
    {
    	if(!f[i])
     	{
        	 f[i] = i;
        	 q[top++] = i;
     	}
     	for(int j = 0 ; q[j] <= f[i] && j < top ; j++)
     	{
        	 f[i * q[j]] = q[j];
         	if(q[j] > n / i)
         		 break;
     	}
    }
}
void devide(int n , int num)
{
    int temp = sqrt(n);
    for(int i = 0; i < top ; i++)
    {
    	if(n == 1)
    		break;
    	if(n % q[i] == 0)
      	    qn[tot[num]][num][0] = q[i];
    	while(n % q[i] == 0)
    	{
    	    n /= q[i];
    	    qn[tot[num]][num][1]++;
    	}
    	tot[num]++;
    }
    if(n > 1)
    {
    	qn[tot[num]][num][0] = n;
    	qn[tot[num]][num][1] = 1;
    	tot[num]++;
    }
}

int gcd(int n , int m)
{
	make_q(10000);
	devide(n , 0);
	devide(m , 1);
	int ans = 1;
	for(int i = 0 , j = 0 ; i < tot[0] || j < tot[1]; )
	{
		if(qn[i][0][0] == qn[j][1][0])
		{
			ans *= min(qn[i][0][1] , qn[j][1][1]) * qn[i][0][0];
			i++;
			j++;
		}
		else
		{
			if(qn[i][0][0] > qn[j][1][0])
				j ++;
			else
				i ++;
		}
	}
	return ans;
}

3.欧几里得算法

  这可以说是最常用也最容易敲的算法了(至少我不知道更好的)。
  首先,对于两个数 n , m n, m n,m,设他们的公因子为 a a a,那么 n n n和 m m m可以表示为 n = k 1 × a n = k_1 \times a n=k1​×a和 m = k 2 × a m = k_2 \times a m=k2​×a,那么 n − m n - m n−m 就可以表示为 ( k 1 − k 2 ) × a (k_1 - k_2)\times a (k1​−k2​)×a,也就是说该数也是 n , m , n − m n , m , n - m n,m,n−m的最大公因子。所以 a a a很明显也是 n , m , m n,m,m n,m,m mod n n n的最大公因子,由此我们就可以想到一种算法:
  对于任意一组 n , m n , m n,m而言,我们可以将其转换为求 n = m , m = n n = m, m = n n=m,m=n mod m m m的解,以此类推,直到 m = 0 m = 0 m=0为止,而这种情况明显是在上一级状况下 n n n是 m m m的倍数的情况下才能成立,所以此时 n n n即为最大公约数。
代码如下

int gcd(int n , int m)
{
	if(n < m)
		swap(n , m);
	return m ? gcd(m , n % m) : n;
}
上一篇:poj3784(对顶堆)


下一篇:【路径规划】基于BBO算法的无人机三维路径规划matlab源码