默认计划
491人加入学习
(0人评价)
【研发工程师】C语言程序设计
价格 ¥ 970.00
该课程属于 名企研发核心能力课 请加入后再学习

OJ165结尾

 

--------------------------------------------------

欧几里得算法:

辗转相除法,用于快速计算两个数字的最大公约数。

 

还可用于快速求解 a*x + b*y = 1方程的一组整数解

gcd(a, b) a与b两个数最大公约数的值。

 

gcd(a, b) => gcd(b, a % b)

大问题缩小成小问题,直到某一层的b值为0,得到答案及a的值。

 

如何证明?

①假设gcd(a, b) = r, 证在b和a%b中也包含r

设:

a = xr

b = yr  其中x, y∈Z,且x,y互素(gcd(x, y) = 1)

a % b = a - kb , k∈Z,k = a // b (//下取整)

          = xr - kyr

          = r(x - ky)

② 证r 为最大

其中:

b = yr

a % b = r(x - ky),

证明y与x - ky互素即可。

证:gcd(y, x - ky) = 1

令gcd(y, x - ky) = d,其中d恒等于1.

设:

y = md

x - ky = nd , 其中m, n ∈ Z

推导==>

y = md

x = d * (n + km)

又由于gcd(x, y) = 1

所以d只能恒为1

-----------------------------------------------

int gcd(int a, int b) {
    if (!b)    return a;
    return gcd(b, a % b);
}

一行写法:

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

 

最小公倍数:

lcm(a, b) = a*b / gcd(a, b)

设:

a = gcd(a, b) * x

b = gcd(a, b) * y

则:a * b = x * y * gcd^2(a, b)

所以:lcm(a, b) = a*b / gcd(a, b)

int lcm(int a, int b) {
    return a / gcd(a, b) * b;
}

最好先除再乘,防止乘爆了int的取值范围。

------------------------------------------------

欧几里得解决二元一次方程组ax + by = 1一组整数值解,a,b,x,y均为整数:

前提a,b互素,即gcd(a, b) = 1

ax + by = 1

推导:

入口:      中间:         尾部边界:

a    b      b    a%b       a    b

x    y      x1   y1        x11  y11

中间:b*x1 + (a%b)*y1 = 1

尾部:a*x11 + b*y11 = 1(边界b=0,取x11=1,y11=0)

 

展开中间:

b*x1 + (a - kb)*y1 = 1

b*x1 + a*y1 - b*ky1 = 1 ,k = a // b (//下取整)

a*y11 + b(x11 - k*y11) = 1

推导至入口:

ax + by =1  ==>

a*y1 + b*(x1 - k*y1) = 1 

 

x是下一层的y

y是下一层的x-ky

 

扩展欧几里得算法:

ax + by = gcd(a,b)

int ex_gcd(int a, int b, int* x, int* y) {
    if (!b) {
        *x = 1, *y = 0;
        return a;
    }
    int xx, yy, ret = ex_gcd(b, a%b, &xx, &yy);
    *x = yy;
    *y = xx - (a%b) * yy;
    return ret;
}

思考题:如何去掉xx yy?

int ex_gcd(int a, int b, int* x, int* y) {
    if (!b) {
        *x = 1, *y = 0;
        return a;
    }
    int ret = ex_gcd(b, a%b, y, x);
    *y -= (a / b) * (*x);
    return ret;
}

 

 

#include <iostream>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int count = 0; // 查看递归次数 

int ex_gcd(int a, int b, int* x, int* y) {
	if (!b)	{
		*x = 1, *y = 0;
		count++;
		return a;
	}
	int xx, yy, ret = ex_gcd(b, a % b, &xx, &yy);
	*x = yy;
	*y = xx - (a / b) * yy;
	count++;
	return ret;
} 

int ex_gcd1(int a, int b, int* x, int* y) {
	if (!b)	{
		*x = 1, *y = 0;
		return a;
	}
	int ret = ex_gcd1(b, a % b, y, x);
	*y -= (a / b) * (*x);
	return ret;
} 

int main(int argc, char** argv) {
	int a, b, x, y;
	while (~scanf("%d%d", &a, &b)) {
		printf("gcd(%d, %d) = %d\n", a, b, ex_gcd1(a, b, &x, &y));
		printf("%d * %d + %d * %d = %d\n", a, x, b, y, ex_gcd(a, b, &x, &y));
		printf("count:%d\n", count);
		count = 0;
	}
	return 0;
}

 

[展开全文]
int gcd(int a, int b) {
  if (!b) return a;
  return gcb(b, a % b);
}

int main() {
  int c, cnt = 0;
  scanf("%d",&c);
  for(int n = 1; n < 1000; n++) {
   for (int m = n + 1; m * m + n* n <= c && m < 1000; m++) {
     if (gcb(m, n) != 1) continue;
     int c1 = m * m + n*n;
     int a = m*m - n * n;
     int b = 2 * m * n;
     if ( gcb(a, b) != 1) continue;
     if (c % c1 != 0) continue;
   }
  }
  printf("%d\n", cnt);
  return 0;
}

欧几里德算法 又名辗转相除法

     1、 用于快速计算两数字的最大公约数,

     2、还可用于快速求解a*x+ b*y= 1方程的一组整数解

   gcd(a, b)  =>  gcd(b, a %b)

    假设gcd(a, b) = r ,证 gcd(b, a %b)有约数 r 且最大值为r

  1、有约数:  a = x r;  b = y r;   x, y 互素(gcd(x, y) = 1)

           a % b = a - k * b ( k 属于整数) = x r - k y r = r( x - k y)

   2、 证明 r 最大:  b = y r ; a % b = r ( x - ky)

     即证 gcb (y, x - k y) = 1

     假设 y = m d ;  x - ky = nd (m, n 属于整数)=>  y = m d;  x = d ( n + k m) 

   => d = 1       

   

int gcb(int a, int b) {
  return (b ? gcb(b, a% b): a);
}

 

ax + by = 1 有整数解, => gcb(a, b) = 1;

          1、gcb(a, b ) = 1

          2 b = 0,  ax = 1, y 任意 

       2:16:37 

       2:20:20

int ex_gcd(int a, int b, int *x, int *y) {
  if (!b) {
    *x = 1, *y = 0;
    return a;
  }
  int xx, yy, ret = ex_gcd(b, a%b, &xx, &yy);
  *x = yy;
  *y = xx - a/b * yy;
  return ret;
}

int main() {

  int a, b, x, y;
  while (~scanf("%d%d", &a, &b)) {
   printf("gcd(%d, %d) = %d\n", a, b, ex_gcd(a, b, &x, &y));
   printf("%d * %d + %d * %d = %d\n", a, x, b, y, a*x + b * y); 
   return 0;
}

 

[展开全文]

授课教师

C++算法工程师

课程特色

视频(31)