이 페이지는 코딩도장 데이터의 읽기 전용 정적 보관본입니다.

Euclid Problem

출처: uva.onlinejudge.org

유클리드가 밝혀낸 바에 따르면, 임의의 정수 A, B에 대해 A와 B의 최대공약수를 D라고 할 때 AX + BY = D 를 만족하는 정수 X와 Y가 존재한다. A와 B가 주어졌을 때 위 식을 만족시키는 X와 Y, 그리고 A와 B의 최대공약수 D를 구하라.

Input

한 줄에 두 개씩의 수가 입력되며 두 수는 각각 A와 B다. A와 B는 스페이스로 구분된다. (A, B < 1,000,000,001).

Output

입력된 각 줄에 대해 각각 스페이스로 구분된 세 개의 정수 X와 Y 그리고 D를 출력한다. 식을 만족하는 X와 Y가 여러 개 있으면, (첫째로) |X| + |Y|가 최소가 되고 (둘째로) X <= Y 인 값을 출력한다.

Sample Input

4 6
17 17

Sample Output

-1 1 2
0 1 17
유클리드호제법

2014/03/20 12:34

pahkey

19개의 풀이가 있습니다.

너무 어려워서 다음 사이트를 참고하였습니다:

파이썬입니다

def euclid(a, b, result=[]):
    m, n = divmod(a,b)
    if n != 0:
        result.append((1,-m))
        return euclid(b, n, result)
    else:
        result.reverse()
        if result:
            x,y = result[0]
            for c in result[1:]:
                x, y = y*c[0], x+y*c[1]
        else:
            x, y = 0, 1
        return x, y, b


print euclid(1071, 1029, [])
print euclid(1029, 1071, [])
print euclid(19332, 78696, [])
print euclid(333, 222, [])
print euclid(333, 333, [])
print euclid(333, 332, [])

2014/03/21 16:15

pahkey

오 리턴에서 다시 자기자신을 실행시킬수가 있군요.. 엄청 짧게 코딩하셨네요, 대단하십니다ㅎ - Onkel, 2014/03/22 01:20
네, 재귀로 해 봤습니다. 금방 만든건 아니고 엄청난 시행착오가 있었습니다. ㅎㅎ - pahkey, 2014/03/22 10:17

파이썬이고, 흔히 알려진 유클리드 알고리즘을 이용했습니다. 코딩이 서툴러서 더 줄일 수 있을것 같은데 잘 못하겠네요.

유클리드 호제법

자연수 A > B가 있을때 다음과 같은 방법으로 최대공약수를 구할 수 있다.

A = Bq_1 + r_1, B = r_1 q_2 + r_2, r_1 = r_2 q_3 + r_3, ... 를 반복한다.

r_i는 점점 줄어들기 때문에 어느 순간 0이 되는데 r_n = 0이라면 r_{n-1}이 바로 최대공약수다.

그리고 위 방법을 조금만 변형하면 임시로 X,Y를 찾을수 있고 적절히 조절해서 문제에서 요구하는 조건을 맞출 수 있습니다.

#
# http://codingdojo.kr/scode/437
#

#
# Finding Linear Combination for Greatest Common Divisor
#
def Euclidean_algorithm(num1, num2):

    # Begin finding quotients and greatest common divisor
    quotient = []
    remainder = [num1, num2]
    while True:
        if remainder[-1] == 0:
            quotient.pop()
            remainder.pop()
            break
        else :
            quotient.append(divmod(remainder[-2],remainder[-1])[0])
            remainder.append(divmod(remainder[-2],remainder[-1])[1])

    gcd = remainder[-1]
    lcm = num1 * num2 / gcd

    # Begin finding a linear combination
    lin_num1 = [1,0]
    lin_num2 = [0,1]

    for quot in quotient:
        lin_num1.append(lin_num1[-2] - quot * lin_num1[-1])
        lin_num2.append(lin_num2[-2] - quot * lin_num2[-1])

    temp_x = lin_num1[-1]
    temp_y = lin_num2[-1]
    to_min = divmod(temp_x, num2/gcd)[0]

    temp = [ [temp_x - to_min*num2/gcd, temp_y  + to_min*num1/gcd],
             [temp_x - (to_min + 1)*num2/gcd, temp_y + (to_min + 1)*num1/gcd] ]

    if abs(temp[0][0]) + abs(temp[0][1]) < abs(temp[1][0]) + abs(temp[1][1]):
        return [gcd, temp[0][0], temp[0][1]]
    elif abs(temp[0][0]) + abs(temp[0][1]) > abs(temp[1][0]) + abs(temp[1][1]):
        return [gcd, temp[1][0], temp[1][1]]
    elif temp[0][0] <= temp[0][1]:
        return [gcd, temp[0][0], temp[0][1]]
    else :
        return [gcd, temp[1][0], temp[1][1]]

#
# Main Part
#

while True:
        input = input("Input two positive integers separated by space : ")
        a, b = input.split()
        A, B = int(a), int(b)
        if str(A) != a or str(B) != b or A > 10E9 or B > 10E9:
            print("The input is incorrect")
        else :
            break

result = Euclidean_algorithm(max(A,B), min(A,B))

if A == max(A,B) :
    X, Y = int(result[1]), int(result[2])
else :
    Y, X = int(result[1]), int(result[2])

print(X, Y, result[0])

2014/03/21 03:50

Onkel

풀긴 했는데 제약 조건이 있습니다.

X, Y값의 범위가 ~1000~1000사이에서만 체크됩니다.

그냥 학부생 수준이라 생각하고 참고만 하세요~

#!/usr/bin/env python

# gcd(greatest common divisor)
def get_gcd(A, B):
    while B != 0:
        r = A%B
        (A,B) = (B,r)
    return A

def get_xy(A, B, D):
    min = -1000
    max = 1000
    sum_xy = 99999999
    for i in range(min,max):
        for j in range(min,max):
            if i>j: # Check1: x <= y
                continue
            if (A*i+B*j) == D:
                temp_sum = abs(i)+abs(j)
                if temp_sum < sum_xy: # Check2: minimum |x|+|y|
                    sum_xy = temp_sum
                else:
                    continue
                (x,y) = (i,j)
    return "%d %d " % (x, y)

def main():
    (N1, N2) = (400, 250)
    D = get_gcd(N1, N2)
    print "Input: %d %d" % (N1, N2)
    print "Output: "+get_xy(N1, N2, D)+str(D)

if __name__ == "__main__":
    main()

2014/07/11 13:33

양승은

파이썬입니다.

def GCM(a,b):
    c = min(a,b)
    while True:
        if (a%c == 0 and b%c == 0):
            return c
        else:
            c-=1

def Euclid(a, b):
    D=GCM(a,b)
    y=0.0
    z=0.0
    while True:
        x=D/a - b*y/a
        w=D/a - b*z/a

        if (x%1==0):
            return (min(x,y), max(x,y), D)
        if (w%1==0):
            return (min(w,y), max(w,y), D)

        y+=1.0
        z-=1.0

print Euclid(4.0, 6.0)

2014/08/12 00:12

정지민

C#으로 작성했습니다. 부끄럽게도 euclid algorithm은 처음 접해 보는 거라 이곳을 참조하게 되었습니다. http://www.trans4mind.com/personal_development/mathematics/numberTheory/euclidsAlgorithmAndExtendedAlgorith.htm 제 코드는 엄밀히 말해서 항상 X <= Y인 값을 출력하지 않습니다. 예를 들어, A = 7, B = 17이 입력되었을 경우, X가 Y보다 큽니다. 일단 푼 데까지만 올리고 다음에 다시 찾아뵙겠습니다.

        public class Euclid
        {
            public int X1 { get; set; }
            public int X2 { get; set; }
            public int Y1 { get; set; }
            public int Y2 { get; set; }
            public int R1 { get; set; }
            public int R2 { get; set; }
            public int Q { get; set; }
            public Euclid(int a, int b)
            {
                X1 = 1;
                X2 = 0;
                Y1 = 0;
                Y2 = 1;
                R1 = b;
                R2 = a%b;
                Q = a/b;
            }
            public void UpdateXs(int x1, int x2)
            {
                X1 = x1;
                X2 = x2;
            }
            public void UpdateYs(int y1, int y2)
            {
                Y1 = y1;
                Y2 = y2;
            }
            public void UpdateRs(int r1, int r2)
            {
                R1 = r1;
                R2 = r2;
            }
        }

        public void FindEuclid(Euclid e)
        {
            if (e.R2 == 0) return;
            var x = e.X1 - e.X2*e.Q;
            var y = e.Y1 - e.Y2*e.Q;
            e.UpdateXs(e.X2, x);
            e.UpdateYs(e.Y2, y);
            var remainder = e.R1%e.R2;
            if (remainder == 0) return;
            e.Q = e.R1/e.R2;
            e.UpdateRs(e.R2, remainder);
            FindEuclid(e);
        }

2015/02/06 21:14

Straß Böhm Jäger

Ruby

참고 알고리즘 : Extended Euclidean, Bézout's identity

bz =->x,y { a,s,b,t = 1,0,0,1
           (x,q,y=y,*x.divmod(y); a,s,b,t=s,a-q*s,t,b-q*t) until y.zero?; [a,b,x] }

Test

# p bz[1071,1029] #=> [-24,25,21]
expect(bz[4,6]).to eq [-1,1,2]
expect(bz[17,17]).to eq [0,1,17]
expect(bz[1071,1029]).to eq [-24,25,21]
expect(bz[78696,19332]).to eq [212,-863,36]

2016/02/29 08:24

rk

확장 유클리드 알고리듬을 적용하였고, 두 수를 나눈 나머지를 통해서 다음 단계로 넘어가므로 재귀호출을 해도 단계가 많지 않을거라 생각되어 재귀로 짰습니다.

def do(a, b):
    q, r = divmod(a, b)
    if r == 0:
        return 0, 1, b
    x, y, g = do(b, r)
    return y, x - q * y, g

data = []
while True:
    s = input()
    if not s:
        break
    data.append([int(x) for x in s.split()[:2]])

for d in data:
    print(do(*d))

2016/03/25 13:04

룰루랄라

def eu(a, b, n = [], depth = 0):
    if depth == 0:
        n = []
    if a < b:
        a, b = b, a
    if a%b == 0:
        return b, n
    n.append(a//b)
    return eu(b, a%b, n, depth + 1)

def s(n):
    i = len(n)
    if i <= 0: return complex(0, 1)
    elif i == 1: return complex(1, -n[1-1])
    elif i == 2: return complex(0, 1) - n[2-1]*complex(1, -n[1-1])
    return s(n[:-2]) - n[-1]*s(n[:-1])

while __name__ == '__main__':
    inpt = list(map(int, input(">>>").split()))
    r_1 = eu(*inpt); r_2 = s(r_1[1]); r_2 = [r_2.real, r_2.imag];
    if inpt[0] < inpt[1]: r_2.reverse()
    print(r_1[0], *r_2)

하얗게 불태웠습니다... 파이썬 3.5.1

2016/04/16 11:51

Flair Sizz

ax+by = gcd(a,b) 의 정수해 (x,y)를 찾기 위해서 bx'+(a%b)y' = gcd(a,b) 를 성립하는 x',y'이 존재한다고 가정합니다.

a%b = a - (a/b)*b이므로 이것을 대입하면 ay' + b(x'-(a/b)y' = gcd(a,b) 입니다. 그리고 b = 0이면 gcd(a,b) = a입니다.

#include <iostream> 
#include <cstdlib> 
#include <cstdio> 
#include <algorithm> 
using namespace std;  

int extgcd(int a,int b,int &x,int &y){ int d = a; if (b != 0){ d = extgcd(b,a%b,y,x);
y -= (a/b)*x; }else{ x = 1; y = 0;
} return d;
}

int main(){ int n,m; while (~scanf("%d %d",&n,&m)){ int x,y; int gcd = extgcd(n,m,x,y);
// x,y,d를 출력한다. printf("%d %d %d\n",x,y,gcd);
} return 0; }

2016/06/02 00:56

iljimae

Delpi 2010

procedure fnEuclidProblem(a, b: Integer; var X, Y, d: Integer);
  function gcd(P, Q: Integer): Integer;
  begin
    if Q = 0 then
      exit(P);
    result := gcd(Q, P mod Q);
  end;

var
  a1, B1, i, j, n1, n2, x1, y1, nMax: Integer;
  bOk: boolean;
begin
  d := gcd(a, b);
  a1 := a div d;
  B1 := b div d;

  X := 0;
  Y := 0;
  nMax := 10000;
  for i := -a1 to a1 do
  begin
    // 최소값 이므로 
    bOk := False;
    n1 := B1 * i;
    // A1*X+B1*Y=1 
    for j := -B1 to i do //X <= Y 인 값
    begin
      if a1 * j + n1 = 1 then
      begin
        n2 := abs(i) + abs(j);
        if nMax > n2 then
        begin
          nMax := n2;
          X := j;
          Y := i;
        end;
      end;
    end;
  end;

end;

procedure TForm4.btnEuclidProblemClick(Sender: TObject);
var
  X, Y, d: Integer;
begin
  fnEuclidProblem(4, 6, X, Y, d);
  Memo1.Lines.Add(format('AX + BY = D => (%d, %d) : x:%d, y:%d, 최대공약수: %d', [4, 6, X, Y, d]));
  fnEuclidProblem(17, 17, X, Y, d);
  Memo1.Lines.Add(format('AX + BY = D => (%d, %d) : x:%d, y:%d, 최대공약수: %d', [17, 17, X, Y, d]));

end;

2016/07/11 13:27

강 경수

자바입니다

package study;

import java.util.Scanner;

public class euclid {

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int A = sc.nextInt();
        int B = sc.nextInt();
        solve(A,B);
    }

    public static void solve(int A, int B){
        int X=0, Y=0, D=0;
        int min;
        min = Math.min(Math.abs(A), Math.abs(B));

        for (int i = 1; i < min + 1; i++) {
            if (A % i == 0 && B % i == 0 && D < i) {
                D = i;
            }
        }

        for (int n = 0; A * X + B * Y != D; n++) {
            for (int j = 0; j <= n; j++) {
                int i=n-j;
                if (A * i + B * j == D) {
                    X = Math.min(i, j);
                    Y = Math.max(i, j);
                    break;
                } else if (0 - A * i + B * j == D) {
                    X = Math.min(0-i, j);
                    Y = Math.max(0-i, j);
                    break;
                } else if (A * i - B * j == D) {
                    X = Math.min(i, 0-j);
                    Y = Math.max(i, 0-j);
                    break;
                }
            }
        }
        System.out.println(X+" "+Y+" "+D);
    }
}

유클리드 호제법같은건 모르고 그냥 일일히 돌렸는데

숫자가 조금 커지니까 오버플로 문제인지 맛이 가네요...

2016/09/08 17:01

JD

import java.util.Scanner;
import java.util.StringTokenizer;

public class euclidproblem {
    public static void main(String args[]) {
        Scanner scan = new Scanner(System.in);

        while(true) {
            String input = scan.nextLine();
            StringTokenizer st = new StringTokenizer(input, " ");
            String token = null;

            token = st.nextToken();
            int A = Integer.parseInt(token);

            token = st.nextToken();
            int B = Integer.parseInt(token);

            getXY(A, B, gcd(A, B));
        }
    }
    static void getXY(int A, int B, int gcd) {

        boolean go = true;
        int start = -1, end = 1;
        while(go) {
            for(int x = start ; x< end; x++) {
                for(int y = start; y< end; y++) {
                    if(A*x + B*y == gcd && x <= y) {
                        System.out.println(x + " " + y +" " +gcd);
                        go = false;
                    }
                }
            }
            end++;
            start--;
        }
    }
    static int gcd(int A, int B) {
        int r = 1;
        int high, low;
        if(A > B) {
            high = A;
            low = B;
        } else {
            high = B;
            low = A;
        }

        while(r!=0) {
            r = high % low;
            high = low;
            low = r; 

        }
        return high;
    }
}

2016/10/12 19:19

코딩초보

import java.util.Scanner;

public class EuclidProblem {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        solve(sc.nextInt(), sc.nextInt());
    }

    private static void solve(int n, int m) {
        int a, b;

        if (n > m) {
            a = m;
            b = n;
        } else {
            a = n;
            b = m;
        }

        int c = gcd(b, a);
        int y = 0;
        while (true) {
            if ((1 - (b / c) * y) % (a / c) == 0) {
                System.out.println(((c - (y * b)) / a) + " " + y + " " + c);
                break;
            }
            y++;
        }
    }

    private static int gcd(int a, int b) {
        int c = a > b ? a % b : b % a;
        return c == 0 ? b : gcd(b, c);
    }
}

2017/05/18 12:15

genius.choi

object EuclidProblem
{
  def SDrs(N : Int): IndexedSeq[Int] = (1 to N / 2) filter(x => N % x == 0)
  def gcd(N1SD: IndexedSeq[Int], N2SD: IndexedSeq[Int], i: Int, j: Int): Int =
    if(N1SD(i) == N2SD(j)) N1SD(i)
    else if(j > 0) gcd(N1SD, N2SD, i, j - 1)
    else if(j == 0) gcd(N1SD, N2SD, i - 1, N2SD.length - 1)
    else 0
  def SEu(N1: Int, N2: Int, gcd : Int, X: Int, Y: Int, SEuL: List[Int]): List[Int] =
    if(N1 * X + N2 * Y == gcd) SEu(N1, N2, gcd, X, Y + 1,SEuL.:+(X).:+(Y))
    else if(Y < 1000) SEu(N1, N2, gcd, X, Y + 1,SEuL)
    else if(X < 1000) SEu(N1, N2, gcd, X + 1, -1000,SEuL)
    else SEuL
  def main(args: Array[String]): Unit ={
    val GCD1 = gcd(SDrs(12),SDrs(15),SDrs(12).length-1,SDrs(15).length - 1)
    val SEuL = List[Int]()
    val Result = SEu(12,15, GCD1, -1000, -1000, SEuL)
    print(Result)
  }
}

탐색 범위 내의 성립하는 X,Y쌍을 전부 출력하게 헀습니다. 유클리드 호제법은 사용하지 않았습니다.

2017/07/19 00:50

S ReolSt

import java.util.Scanner;

public class test {
    static long GCD(long a, long b) {
        if (b == 0) {
            return a;
        } else {
            return GCD(b, a % b);
        }
    }

    /*
     A = aD, B = bD
     aDX + bDY = D
     aX + bY = 1     
     */

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long A, B, D, a, b, X, Y;
        A = sc.nextLong();
        B = sc.nextLong();
        D = GCD(A, B);
        a = A / D;
        b = B / D;

        for (long y = 0; ; y++) {
            for (long x = 0; x <= y; x++) {             
                if (a * x + b * y == 1) { X = x; Y = y; }
                else if (a * x - b * y == 1) { X = x; Y = -y; }
                else if (b * y - a * x == 1) { X = -x; Y = y; }
                else if (a * x + b * y == -1) { X = -x; Y = -y; }
                else continue;

                if (X > Y) { long t = X; X = Y; Y = t; }
                System.out.printf("%d %d %d\n", X, Y, D);
                return;
            }
        }            

    }
}

|X| <= |Y| 로 풀었네요. X <= Y 로 하면 부호가 너무 복잡해져서;; X, Y를 양의 정수로 한정하면 훨씬 쉬울 것 같습니다.

2017/08/22 22:01

Noname

import java.util.Scanner;

public class EuclidProblem {

    public static int gcd(int a, int b) {
        while (b != 0) {
          int temp = a % b;
          a = b;
          b = temp;
        }
        return Math.abs(a);
      }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);

        for(int i=0; i<2; i++){
            String[] numbers = sc.nextLine().split(" ");
            int a = Integer.parseInt(numbers[0]);
            int b = Integer.parseInt(numbers[1]);
            int result = gcd(a,b);
            int x = 0;
            int y = 0;

            int count = 0;
            while(true){
                if(result == a * x + b * y){
                    break;
                }else{
                    if(count % 3 == 0){
                        x--;
                    }else if(count % 3 == 1){
                        x++;
                        y++;
                    }else if(count % 3 == 2){
                        x--;
                    }
                    count++;
                }
            }
            System.out.println(x + " " + y + " " +result);
        }
        sc.close();

    }

}

2018/04/10 23:57

김태훈

import java.util.Scanner;

public class EuclidProblem {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] AB = sc.nextLine().split(" ");
        int A = Integer.valueOf(AB[0]), B = Integer.valueOf(AB[1]), Gcd = 0;
        for (int i = 1; i < (A > B ? A : B) + 1; i++)
            if (i <= A && A % i == 0 && i <= B && B % i == 0)
                Gcd = i;
        outerLoop: for (int i = 0; i < (A > B ? A : B) + 1; i++)
            for (int j = 0; j > (A > B ? B : A) * -1 - 1; j--)
                if (A * (A > B ? i : j) + B * (A > B ? j : i) == Gcd) {
                    System.out.println((A > B ? i : j) + " " + (A > B ? j : i) + " " + Gcd);
                    break outerLoop;
                }
    }
}

2018/05/31 00:49

김지훈

def gcd(a,b):
    while b != 0:
        a,b = b,a%b
    return a

while 1:
    a,b = map(int,input('a b: ').split())
    if not a: break
    D = gcd(a,b)
    y = lambda x: (D-a*x)/b
    id = 0
    while 1:
        if not y(id)%1: break
        id -= 1
    print(id,int(y(id)),D)

AX+BY=D, X<=Y 를 만족하는 정수해는 2사분면에 존재한다
따라서 X <= 0 인 범위에서 정수 조합을 찾는다

2018/07/22 22:20

Creator

def GCD(A, B):
    if A < B:
        A, B = B, A

    if B==0:
        return A
    A, B = B, A%B
    return GCD(A,B)

#A, B = 4, 6
#A, B = 17, 17
A, B = map(int, input('두 개씩의 수 입력:').split())
gcd = GCD(A, B)
a, b = A//gcd, B//gcd
x, y = 0, 1
while True:
    d = a*x - b*y
    if d==1:
        print(x,-y,gcd)
        break
    elif d==-1:
        print(-x,y,gcd)
        break
    elif d>0:
        y += 1
    else:
        x += 1

2023/12/28 19:08

insperChoi

목록으로