티스토리 뷰

알고리즘 공부

C언어 분수 대소비교

소심야채 2022. 12. 28. 18:21

https://www.acmicpc.net/problem/26519

 

26519번: 함수와 최소 스패닝 트리

첫 번째 줄에 정수 V, E, a가 공백으로 구분되어 주어진다. (1V100; 1E250; 1000a1000; a0) 다음 E개의 줄에 간선의 정보를 나타내는 네 정수 X, Y, bi, ci

www.acmicpc.net

위 문제를 풀다가 정밀도 이슈가 있다고 생각되어 구조체를 이용하여 분수를 구현하였습니다.

 

ab<cd

우리가 흔히 알고있는 공식을 이용하면 a*d < b*c로 판별할 수 있으나 각각의 변수는 안전하지만 곱하는 순간 오버플로우에 취약합니다.

 

예를 들어 396519814<478923456

구하기 위해서는

396523456<478919814

와 같이 수가 급격하게 커지게 됩니다. 분수를 기울기로 접근하자면 아래와 같은 그림으로 표현할 수 있습니다.

파랑색의 숫자는 식의 좌항을 표현한 것이고 초록색의 숫자는 우항을 변형하여 나온 숫자입니다.

478923456=3965+82419814+3642

396519814<15and8243642>15

 

위와 같이 기울기를 통해 대소비교가 가능하며 이점으로는 판별식에서 수가 급격하게 커지는 것을 어느정도 방지할 수 있습니다.

 

ab<cd={a<c,if b == d(ac)d<c(bd)else if b > da(db)<(ca)belse

두 분수가 같은지도 응용하면 쉽게 구할 수 있습니다.

 

[코드]

typedef struct Fraction {
   ll numerator;    // 분자
   ll denominator;  // 분모

   bool operator < (Fraction rhs) const {
      if(denominator == rhs.denominator)
         return numerator < rhs.numerator;

      if(denominator > rhs.denominator) {
         return (numerator-rhs.numerator) * rhs.denominator < (denominator-rhs.denominator) * rhs.numerator;
      }
      return numerator * (rhs.denominator - denominator) < denominator * (rhs.numerator - numerator);
   }

} Fraction;

 

댓글