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

문제

N장의 카드에 써져 있는 숫자가 주어졌을 때, M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 구해 출력하시오.

입력

첫째 줄에 카드의 개수 N(3 ≤ N ≤ 100)과 M(10 ≤ M ≤ 300,000)이 주어진다. 둘째 줄에는 카드에 쓰여 있는 수가 주어지며, 이 값은 100,000을 넘지 않는 양의 정수이다.

합이 M을 넘지 않는 카드 3장을 찾을 수 있는 경우만 입력으로 주어진다.

출력

첫째 줄에 M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 출력한다.

풀이

부르트포스 알고리즘을 활용하는 문제로써 무작정 대입하여 해결하면 된다.

  1. n과 m을 입력받고 n 크기의 배열을 생성한다.
  2. 배열에 n 개의 값을 입력받는다.
  3. 3중 for문을 사용하여 모든 경우의 수를 더해본다
    1. 3개의 값을 입력받기 때문에 1번째 for문은 n - 2 만큼 반복한다
    2. 2번재 for문은 i + 1 부터 n 까지 만큼 반복한다
    3. 3번재 for문은 j+ 1 부터 n 까지 만큼 반복한다
    4. 3개의 값을 모두 더한 다음 m과 같다면 해당 값을 반환
    5. 더한 값이 m보다  작다면 현재 저장된 값과 비교하여 더 큰값을 저장하고 반복
    6. 반복이 끝나면 저장된 값을 반환
  4. 결과를 출력

아래는 이를 구현한 코드이다.

중간에  값을 반환하기 위해 연산하는 부분은 메서드로 분리하여 작성하였다.

더보기
import java.util.Scanner;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();


        int[] arr = new int[n];

        for(int i = 0; i < n; i++){
            arr[i] = sc.nextInt();
        }

        System.out.println(sum(arr, m));
    }

    public static int sum(int[] arr, int m){
        int sum, result = 0;

        for(int i = 0; i < arr.length-2; i++){
            for(int j = i+1; j < arr.length; j++){
                for(int k = j+1; k < arr.length; k++){
                    sum = arr[i] + arr[j] + arr[k];
                    if (sum == m){
                        return sum;
                    }else if (sum <= m){
                        result = Math.max(result, sum);
                    }
                }
            }
        }
        return result;
    }
}

 

'코테 > 백준' 카테고리의 다른 글

3009번 네 번째 점  (1) 2025.02.11
11653번 소인수분해  (1) 2025.02.10
2581번 소수  (1) 2025.02.08
1978번 소수 찾기  (1) 2025.02.07
9506번 약수들의 합  (1) 2025.02.06

문제

세 점이 주어졌을 때, 축에 평행한 직사각형을 만들기 위해서 필요한 네 번째 점을 찾는 프로그램을 작성하시오.

입력

세 점의 좌표가 한 줄에 하나씩 주어진다. 좌표는 1보다 크거나 같고, 1000보다 작거나 같은 정수이다.

출력

직사각형의 네 번째 점의 좌표를 출력한다.

풀이

문제에서 주어진 좌표를 자세히 보면 직사각형이기에 서로 두번씩 반복됨을  알수있다.

예제
30 20
10 10
10 20

출력
30 10

 

그러니깐 단순하게 생각하면 x좌표와 y좌표에서 각각 1번씩만 나온 숫자를 출력하면 된다.

결국 중복을 어떻게 처리하는지 구현하는 문제이다.

 

- 단순하게 풀이

더보기
  1. 모든 값을 따로 입력받는다.
  2. 1번째 x의 값과 2번째 x의 값을 비교해서 서로 다르고
    1. 1번째 x의 값과 3번째 x의 값이 같다면 1번째 값 저장
    2. 2번째 x의 값과 3번째 x의 값이 같다면 2번재 값 저장
  3. y도 동일하게 진행
  4. 저장된 값을 형식에 맞춰 출력
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();

        int c = sc.nextInt();
        int d = sc.nextInt();

        int ra = sc.nextInt();
        int rb = sc.nextInt();

        if (a != c){
            if (a == ra) ra = c;
            else if (c == ra) ra = a;
        }
        if (b != d){
            if (b == rb) rb = d;
            else if (d == rb) rb = b;
        }
        
        System.out.printf("%d %d", ra, rb);
    }
}

 

이번 문제는 입력받을 수의 숫자가 정해져있어서 굳이 반복문을 쓸 필요가 없었다.

 

- 해시맵을 활용하여 풀이

더보기
  1. 두개의 해시맵을 생성
  2. 반복문으로 3번씩 반복한다.
    1. a가 mapa의 키와 같다면 값 증가
    2. 아니면 새로 추가
    3. 이 작업을 b에서도 동일하게 진행
  3. 맵을 반복하여 값이 1인 키를 찾아 형식에 맞춰 출력
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        HashMap<Integer, Integer> mapa = new HashMap<>();
        HashMap<Integer, Integer> mapab = new HashMap<>();

        Scanner sc = new Scanner(System.in);
        int a ,b;

        for (int i = 0; i < 3; i++) {
            a = sc.nextInt();
            b = sc.nextInt();

            if(mapa.containsKey(a)) mapa.put(a, mapa.get(a) + 1);
            else mapa.put(a, 1);

            if(mapab.containsKey(b)) mapab.put(b, mapab.get(b) + 1);
            else mapab.put(b, 1);
        }

        for (Map.Entry<Integer, Integer> entry : mapa.entrySet()) {
            if(entry.getValue() == 1) System.out.print(entry.getKey() + " ");
        }
        for (Map.Entry<Integer, Integer> entry : mapab.entrySet()) {
            if(entry.getValue() == 1) System.out.print(entry.getKey());
        }
    }
}

 

제일 처음 생각한 방법이지만 제일 느리고 복잡한 방법이였다.

이전에 중복을 찾을때 해시맵을 사용한 기억이 있어서 이를 활용해보았었지만

이 문제에는 그닥 좋은 방법은 아닌 것 같다.

 

 

'코테 > 백준' 카테고리의 다른 글

2798번 블랙잭  (1) 2025.02.13
11653번 소인수분해  (1) 2025.02.10
2581번 소수  (1) 2025.02.08
1978번 소수 찾기  (1) 2025.02.07
9506번 약수들의 합  (1) 2025.02.06

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

문제

정수 N이 주어졌을 때, 소인수분해하는 프로그램을 작성하시오.

입력

첫째 줄에 정수 N (1 ≤ N ≤ 10,000,000)이 주어진다.

출력

N의 소인수분해 결과를 한 줄에 하나씩 오름차순으로 출력한다. N이 1인 경우 아무것도 출력하지 않는다.

풀이

간단한 소인수분해 문제이다.

 

처음에는 for문을 써서 반복을 하려고 했지만 그렇게 하기엔 n의 범위가 정해져있지도 않고 랜덤하기에

while문을 이용해서 n의 값이 1이 되면 멈추게 만들었다.

  1. 정수 n을 입력받고, n을 나눌 값 i를 2로 초기화 해준다.
  2. while문으로 n이 1이 아니면  반복시킨다. (더이상 나눌값이 없다면 멈춤)
  3. n을 i로 나눈 나머지가 0이라면
    1. i를 출력한다.
    2. n의 값을 n/i 로 설정한다.
    3. i의 값을 2로 재설정한다.
  4. 나머지가 0이 아니라면 i의 값을 증가시킨다.
  5. 더이상 나눌 값이 없으면  n이 1이 되므로 반복문은 종료된다.
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int i = 2;

        while(n != 1){
            if (n % i == 0) {
                System.out.println(i);
                n /= i;
                i = 2;
            }else {
                i++;
            }
        }
    }
}

'코테 > 백준' 카테고리의 다른 글

2798번 블랙잭  (1) 2025.02.13
3009번 네 번째 점  (1) 2025.02.11
2581번 소수  (1) 2025.02.08
1978번 소수 찾기  (1) 2025.02.07
9506번 약수들의 합  (1) 2025.02.06

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

문제

자연수 M과 N이 주어질 때 M이상 N이하의 자연수 중 소수인 것을 모두 골라 이들 소수의 합과 최솟값을 찾는 프로그램을 작성하시오.

예를 들어 M=60, N=100인 경우 60이상 100이하의 자연수 중 소수는 61, 67, 71, 73, 79, 83, 89, 97 총 8개가 있으므로, 이들 소수의 합은 620이고, 최솟값은 61이 된다.

입력

입력의 첫째 줄에 M이, 둘째 줄에 N이 주어진다.

M과 N은 10,000이하의 자연수이며, M은 N보다 작거나 같다.

출력

M이상 N이하의 자연수 중 소수인 것을 모두 찾아 첫째 줄에 그 합을, 둘째 줄에 그 중 최솟값을 출력한다. 

단, M이상 N이하의 자연수 중 소수가 없을 경우는 첫째 줄에 -1을 출력한다.

풀이

주어진 영역내의 소수의 합과 최소값을 구해야 하므로

에라토스테네스의 체를 활용하였다.

 

에라토스테네스의 체 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 에라토스테네스의 체 수학에서 에라토스테네스의 체는 소수를 찾는 빠르고 쉬운 방법이다. 고대 그리스 수학자 에라토스테네스가 발견하였다. 2부터 소수를

ko.wikipedia.org

 

해당 공식은 소수인 2 부터 시작하여 2의 배수를 모두 지우고, 이 다음 소수인 3의 배수를 모두 지우고...

이를 활용하면 주어진 범위내의 모든 소수를 쉽게 찾을수 있다.

  1. 정수 m과 n을 입력받고 boolean 타입의 배열을 n+1 크기로 생성한다.
  2. 반복문을 2부터 시작하여 배열의 값이 false인  경우 해당 값의 배수를 모두 true로 바꾼다.
  3. 이렇게 하면 모든 소수는 false로 배열에 저장된다.
  4. 나머지 0과 1은 따로 false 처리 한다.
  5. m ~ n 범위의 배열중에서 값이 false인 배열을 찾는다.
  6. 만약 sum이 0이라면 (첫번째 값이라면) 최소값이므로 저장한다.
  7. sum에 모든 소수를 더해준다.
  8. 최종적으로 sum이 0이라면 소수가 없는것이므로 -1을 출력하고 그외에는 sum과 최소값을  출력한다.

아래는 이를 구현한 코드이다.

// 에라토스테네스의 체
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int m = sc.nextInt();
        int n = sc.nextInt();

        int min = 0;
        int sum = 0;

        boolean[] arr = new boolean[n+1];

        for (int i = 2; i < n+1; i++) {
            if (!arr[i]) {
                for (int j = i+i; j < n+1; j+=i) {
                    arr[j] = true;
                }
            }
        }

        arr[0] = true;
        arr[1] = true;

        for (int i = m; i < n+1; i++) {
            if (!arr[i]) {
                if(sum == 0) min = i;
                sum += i;
            }
        }

        if (sum == 0){
            System.out.println(-1);
        } else{
            System.out.println(sum);
            System.out.println(min);
        }

    }
}

 

이번 문제를 풀면서 몇번씩 쓰고 지우고를 반복했다.

뭔가 잘못된것 같으면 모두 주석처리하거나 다 지워버리고 처음부터 다시 생각하는게 도움이 되는 것 같다.

'코테 > 백준' 카테고리의 다른 글

3009번 네 번째 점  (1) 2025.02.11
11653번 소인수분해  (1) 2025.02.10
1978번 소수 찾기  (1) 2025.02.07
9506번 약수들의 합  (1) 2025.02.06
2501번 약수 구하기  (0) 2025.02.06

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

문제

주어진 수 N개 중에서 소수가 몇 개인지 찾아서 출력하는 프로그램을 작성하시오.

입력

첫 줄에 수의 개수 N이 주어진다. N은 100이하이다. 다음으로 N개의 수가 주어지는데 수는 1,000 이하의 자연수이다.

 

풀이

주어진 수 N개 중 소수를 찾으면 되는 문제이기에 나는 이렇게 풀었다.

  1. N을 입력받아 반복문으로 입력을 받는다.
  2. 입력 받은 수 m 의 값이 1보다 같거나 작으면  continue 한다.
  3. 약수가 있는지 검사하고 약수가 존재하면 sum+1을 한다.
  4. 소수는 약수가 1이고, 아니면 1 이상의 값을 가진다.
  5. 약수가 1인 값만 count한다.
  6. 결과를 출력한다.
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m, count = 0;
        int sum;

        for (int i = 0; i < n; i++) {
            m = sc.nextInt();

            if(m <= 1) continue;

            sum = 0;
            for (int j = 1; j <= m/2; j++) {
                if(m%j == 0){
                    sum += j;
                }
            }
            if(sum == 1) count++;
        }
        System.out.println(count);
    }
}

'코테 > 백준' 카테고리의 다른 글

11653번 소인수분해  (1) 2025.02.10
2581번 소수  (1) 2025.02.08
9506번 약수들의 합  (1) 2025.02.06
2501번 약수 구하기  (0) 2025.02.06
5086번 배수와 약수  (1) 2025.02.05

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

문제

어떤 숫자 n이 자신을 제외한 모든 약수들의 합과 같으면, 그 수를 완전수라고 한다.

예를 들어 6은 6 = 1 + 2 + 3 으로 완전수이다.

n이 완전수인지 아닌지 판단해주는 프로그램을 작성하라.

출력

테스트케이스 마다 한줄에 하나씩 출력해야 한다.

n이 완전수라면, n을 n이 아닌 약수들의 합으로 나타내어 출력한다(예제 출력 참고).

이때, 약수들은 오름차순으로 나열해야 한다.

n이 완전수가 아니라면 n is NOT perfect. 를 출력한다.

풀이

2025.02.06 - [코테/백준] - 2501: 약수 구하기

 

2501: 약수 구하기

https://www.acmicpc.net/problem/2501문제어떤 자연수 p와 q가 있을 때, 만일 p를 q로 나누었을 때 나머지가 0이면 q는 p의 약수이다. 6을 예로 들면6 ÷ 1 = 6 … 06 ÷ 2 = 3 … 06 ÷ 3 = 2 … 06 ÷ 4 = 1 … 26 ÷ 5 = 1

jhss9747.tistory.com

이전에 풀었던 약수 구하기 문제의 응용버전이다.

위 문제에서 풀었듯이 n의 약수를 먼저 구하고, 약수를 모두 더한 값이 n과 같다면 합을 출력한다.

  1. while문으로 무한 반복하며, n을 입력받고 n이 -1이라면 멈춘다.
  2. 완전수는 n 자기자신을 제외한 모든 약수의  합이므로 n/2 의 값 만큼 for문을 반복한다.
  3. 만약 약수라면 result 문자열에 형식에 맞춰 약수를 추가하고, sum에 값을 더한다.
  4. for문이 끝나고 result의 마지막에 불필요한 ' + ' 를 제거한다.
  5. if문으로 n과 sum값이 같은지 확인하여 같다면 result를 출력한다.
  6. 같지 않다면 n is NOT perfect. 를 반환한다.

아래와 같이 코드로 구현하였다.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n ,sum;
        String result;

        while(true){
            n = sc.nextInt();
            sum = 0;
            result = " = ";

            if (n == -1) break;

            for (int i = 1; i <= n/2; i++) {
                if(n%i == 0){
                    result = result + i + " + ";
                    sum += i;
                }
            }
            result = result.substring(0, result.length()-3);

            if (sum == n) {
                System.out.println(n + result);
            } else{
                System.out.println(n + " is NOT perfect.");
            }
        }

    }
}

'코테 > 백준' 카테고리의 다른 글

2581번 소수  (1) 2025.02.08
1978번 소수 찾기  (1) 2025.02.07
2501번 약수 구하기  (0) 2025.02.06
5086번 배수와 약수  (1) 2025.02.05
2869번 달팽이는 올라가고 싶다  (0) 2025.01.27

어떤 자연수 p와 q가 있을 때, 만일 p를 q로 나누었을 때 나머지가 0이면 q는 p의 약수이다. 

6을 예로 들면

  • 6 ÷ 1 = 6 … 0
  • 6 ÷ 2 = 3 … 0
  • 6 ÷ 3 = 2 … 0
  • 6 ÷ 4 = 1 … 2
  • 6 ÷ 5 = 1 … 1
  • 6 ÷ 6 = 1 … 0

그래서 6의 약수는 1, 2, 3, 6, 총 네 개이다.

두 개의 자연수 N과 K가 주어졌을 때, N의 약수들 중 K번째로 작은 수를 출력하는 프로그램을 작성하시오.

 

풀이

약수를 구하는 방법은 n을 나눴을때 나머지가  0인 값이 바로 약수이다.

  1. for문을 사용해서  i를 0부터 n까지 반복
  2. n 과 i의 나머지가 0이라면 count 를 증가시킨다.
  3. count가 k와 같아지면 for문을 멈추고 k를 출력한다.
  4. 반복문이 끝나면 count가 k보다 작은지 확인하고 작다면 0을 출력한다.

이를 코드로 구현하면 아래와 같다.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        int count = 0;

        for (int i = 1; i <= n; i++) {
            if(n%i == 0){
                count++;
                if(count == k) {
                    System.out.println(i);
                    break;
                }
            }
        }
        if(count < k){
            System.out.println(0);
        }
    }
}

'코테 > 백준' 카테고리의 다른 글

1978번 소수 찾기  (1) 2025.02.07
9506번 약수들의 합  (1) 2025.02.06
5086번 배수와 약수  (1) 2025.02.05
2869번 달팽이는 올라가고 싶다  (0) 2025.01.27
1193번 분수찾기  (0) 2025.01.24

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

 

두 수가 주어졌을 때, 다음 3가지 중 어떤 관계인지 구하는 프로그램을 작성하시오.

  1. 첫 번째 숫자가 두 번째 숫자의 약수이다.
  2. 첫 번째 숫자가 두 번째 숫자의 배수이다.
  3. 첫 번째 숫자가 두 번째 숫자의 약수와 배수 모두 아니다.

약수와 배수를 구하는 문제로써

  1. A 가 B의 약수 -> B/A 의 나머지가 0이면 약수
  2. A 가 B의 배수 -> A/B 의 나머지가 0이면 배수
  3. 모두 아니라면  약수와 배수가 모두 아니다

라고 생각했고 이를 코드로 구현하면 다음과 같다.

import java.util.Scanner;

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

        while(true){
            int a = sc.nextInt();
            int b = sc.nextInt();

            if (a == 0 && b == 0) break;

            if(b%a == 0){
                System.out.println("factor");
            }
            else if(a%b == 0){
                System.out.println("multiple");
            }
            else{
                System.out.println("neither");
            }
        }
    }
}

 

while문으로 무한 반복으로 입력을 받고, a와 b가 모두 0일때 입력을 멈추기로 했다.

그 외에 조건들은 모두 if문으로 나누어주었다.

'코테 > 백준' 카테고리의 다른 글

9506번 약수들의 합  (1) 2025.02.06
2501번 약수 구하기  (0) 2025.02.06
2869번 달팽이는 올라가고 싶다  (0) 2025.01.27
1193번 분수찾기  (0) 2025.01.24
2563번 색종이  (0) 2025.01.24

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

 

이번 문제는 완전히 수학 문제였다.

 

먼저 문제에서는 달팽이가 막대를 타고 올라가는데 조건은 다음과 같다

- 막대의 높이는 V이다.
- 낮에 A 미터를 올라가고
- 밤에 B 미터를 미끄러진다
- 정상에서는 미끄러지지 않는다

최종적으로 달팽이가 막대를 올라가는데 며칠이 걸리는지 출력하면 된다.

 

반복문을 쓰면 간단하게 해결가능한 문제라고 생각하여 바로 작성해보았다.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        int v = sc.nextInt();
        int count = 1;
        int h = 0;

        while(true){
            h += a;
            if(h >= v){
                break;
            }
            h -= b;
            
            if(h >= v){
                break;
            }

            count++;
        }
        System.out.println(count);
    }
}

 

간단하게 while문으로 반복하면서 값을 비교하고 count를 출력하는 코드이다.

하지만 시간제한 0.25초 라는 제한이 있어서  이대로 제출하면 시간초과가 난다.

 

문제를 어떻게 풀까 많이 고민했는데 이 반례를 보고 규칙을 찾을 수 있었다.

input : 12 10 102
output : 51
answer : 46

 

먼저 달팽이가 하루에 올라갈 수 있는 높이를 계산하였다.

(올라간 거리) - (내려간 거리) = (하루동안 올라갈 수 있는 높이)
A - B = H

 

그 다음 달팽이가 마지막날에 도달하는 높이를 구한다.

(막대 높이) - (내려간 거리) = (도달 높이)
V - B = mH

 

왜 마지막날에 도달하는 높이를 따로 구하냐면,

달팽이는 막대의 끝에 도달하면 더이상 미끌어지지 않는다는 조건이 있기 때문에

최대 높이에서 미끌어진 거리까지가 달팽이의 마지막 날이 될 수 있기 때문이다.

 

이제 이렇게 구해진 값들을 나누면 달팽이가 막대를 등반하기 위해여 걸리는 총 날짜가 나온다.

(도달 높이) / (하루동안 올라갈 수 있는 높이)
mH / H = result

 

하지만 여기서 문제가 하나 생긴다.

만약에 나눈 숫자가 정수가 아니라 소수점 자리로 나온다면?

예를 들어

5 1 6

 

이렇게 값이 주어지는 경우 이러한 결과가 나온다.

A - B = 5 - 1 = 4
V - B = 6 - 1 = 5
5 / 4 = 1.25

 

손으로 그려봐도 달팽이가 정상까지 가는데 2일이 걸리므로

소수자리가 나온다면 올림해주면 된다.

 

그래서 처음에 해당 결과값을 float 형식으로 받아와서 소수점을 올림처리 하는 코드를 작성하였다.

하지만 3번째 예제에서 답이 다르게 나왔는데 아래와 같이 입력이 주어졌을 경우

100 99 1000000000

 

아래와 같이 출력되었다.

999999872 // 출력된 값
999999901 // 정답

 

이유를 알수없어서 검색을 해보았는데 부동 소수점 연산의 정확도 문제라고 한다.

더보기
더보기

부동 소수점 연산의 정확도 문제는 컴퓨터 과학에서 자주 발생하는 문제입니다. 이를 이해하기 위해서는 부동 소수점 숫자가 어떻게 표현되는지 알아야 합니다.

부동 소수점 숫자는 컴퓨터에서 다음과 같은 형식으로 저장됩니다:

  • 부호 비트: 숫자가 양수인지 음수인지를 나타냅니다.
  • 지수: 숫자의 크기를 나타냅니다.
  • 가수: 숫자의 정확한 값을 나타냅니다.

이러한 형식은 매우 큰 숫자나 매우 작은 숫자를 표현할 수 있게 해주지만, 정확한 값을 표현하는 데는 한계가 있습니다. 특히, 부동 소수점 숫자는 근사값으로 저장되기 때문에 정확한 값을 표현하지 못할 때가 있습니다. 이는 다음과 같은 이유로 발생합니다:

  1. 정밀도 제한: 부동 소수점 숫자는 제한된 비트 수로 표현되기 때문에, 매우 큰 숫자나 매우 작은 숫자를 표현할 때 정밀도가 떨어질 수 있습니다. 예를 들어, 999999901과 같은 큰 숫자를 부동 소수점 형식으로 변환하면 근사값으로 저장되기 때문에 999999872와 같은 값이 나올 수 있습니다.
  2. 반올림 오차: 부동 소수점 연산에서는 반올림 오차가 발생할 수 있습니다. 이는 소수점 이하의 값을 반올림할 때 발생하는 오차로, 특히 여러 번의 연산을 거치면서 누적될 수 있습니다.
  3. 표현 범위 제한: 부동 소수점 숫자는 표현할 수 있는 범위가 제한되어 있습니다. 이 범위를 벗어나는 숫자는 근사값으로 저장되기 때문에 정확한 값을 표현하지 못할 수 있습니다.

이러한 이유로 인해 부동 소수점 연산에서 오차가 발생할 수 있습니다. 이를 해결하기 위해서는 정수 연산을 사용하는 것이 좋습니다. 정수 연산은 정확한 값을 유지할 수 있기 때문에 부동 소수점 연산에서 발생하는 오차를 피할 수 있습니다.

이것을 해결하기 위해 if문을 사용하여 나머지가 0인 경우에는 그대로 출력하게 하고,

그 외에는 +1을 하도록 하게 코드를 수정하였다.

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt(); // 올라간 거리
        int b = sc.nextInt(); // 내려간 거리
        int v = sc.nextInt(); // 막대

        if((v - b) % (a-b) == 0){
            System.out.println((v - b) / (a-b));
        } else{
            System.out.println(((v - b) / (a-b))+1);
        }
    }
}

 

이걸로 문제를 해결할 수 있었다.

'코테 > 백준' 카테고리의 다른 글

2501번 약수 구하기  (0) 2025.02.06
5086번 배수와 약수  (1) 2025.02.05
1193번 분수찾기  (0) 2025.01.24
2563번 색종이  (0) 2025.01.24
2903번 중앙 이동 알고리즘  (0) 2025.01.24

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

 

아래 그림과 같은 무한한 배열이 주어진다.

그림 1

이와 같이 나열된 분수들을 1/1 → 1/2 → 2/1 → 3/1 → 2/2 → … 과 같은 지그재그 순서로

차례대로 1번, 2번, 3번, 4번, 5번, … 분수라고 할때  X번째 분수를 구하는 문제이다.

 

입력 범위가 X(1 ≤ X ≤ 10,000,000)로 꽤 넓고 시간제한은 0.5초로 짧다.

 

처음에 지그제그가 무슨 말이지 하고 직접 그림판으로 그려보니 이해가 되었다.

그림판으로 선을 그었다.

 

이 문제를 단순히 보이는 대로 배열로 풀었다간 무조건 시간 초과가 날 것이다.

그리고 지그제그로 되어있어 어떤 특정한 패턴을 찾아야 했다.

 

그래서 일단 지그제그 순서대로 표를 만들어서 써보았다.

순번 1 2 3 4 5
1 1/1        
2 1/2 2/1      
3 3/1 2/2 1/3    
4 1/4 2/3 3/2 4/1  
5 5/1 4/2 3/3 2/4 1/5

이렇게 하나하나 작성하고 보니 어떤 특정한 패턴이 보이기 시작했다.

 

1. 홀/짝수 번호에서 분모와 분자의 순서가 뒤바뀐다.

2. 최대 분모와 분자는 순번을 넘어가지 않는다. ex) 3번은 3을 넘지않음

3. 분모와 분자는 서로 1씩 늘어나거나 줄어든다.

 

이렇게 세가지 규칙을 찾아내었고 이걸 코드에 어떻게 적용할까 고민하였다.

일단 고려사항으로는

 

1. for문의 반복횟수를 최대한 줄여서 시간 복잡도를 줄여야 하고,

2. 홀/짝수 번호에서 분모와 분자의 위치를 서로 바꾸고 1씩 줄이거나 늘려야 한다.

 

그렇게 고민하다 생각해낸 방법은

해당 순번에서 최대/최소 값을 구해서 if문으로 분리하고, 연산해주는 방법을 떠올렸다.

그리고 홀/짝은 순번의 나머지 값을 비교하는 방식으로 분리하였다.

 

이제 코드로 구현해보면...

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int count = 0;
        int sum = 0;

        while(true){
            if (n==1){
                System.out.println("1/1");
                break;
            }

            if(n <= sum){
                if (count%2==0){ // 짝수
                    System.out.printf("%d/%d",n-(sum-count),count-(n-(sum-count))+1);
                    break;
                }
                else{            // 홀수
                    System.out.printf("%d/%d",count-(n-(sum-count))+1,n-(sum-count));
                    break;
                }
            }
            count++;      // 카운트
            sum += count; // 최대값
        }
    }
}

 

while문으로 무한 반복을 돌리고

1의 경우에는 예외처리를 해주었고

count와 sum을 만들어서 각 순번과 최대값을 구할 수 있게 했다.

 

중간에 수식이 꽤 난잡한데 풀어서 정리하자면

(sum-count)

- 최대값과 카운트를 빼서 해당 순번의 최소값을 구했다.

n-(sum-count)

- n과 최소값을 빼서 분모/자를 만들었다.

count-(n-(sum-count))+1

- 분/모자 값에 순번을 빼서 역의 값이 나오도록 했다. 1로 값을 세부 조정했다.

 

이렇게 쓰고나니깐 뭔가 더 많이 복잡한데 일단 문제를 해결하긴 했다.

 

메모리는 17748 kb , 시간은 176ms가 걸렸다.

 

역시 문제를 풀때는 종이에 한번 써보는게 생각을 정리하는데 많은 도움이 되는것 같다.

'코테 > 백준' 카테고리의 다른 글

5086번 배수와 약수  (1) 2025.02.05
2869번 달팽이는 올라가고 싶다  (0) 2025.01.27
2563번 색종이  (0) 2025.01.24
2903번 중앙 이동 알고리즘  (0) 2025.01.24
2292번 벌집  (1) 2025.01.23

+ Recent posts