www.acmicpc.net/problem/1963

 

1963번: 소수 경로

소수를 유난히도 좋아하는 창영이는 게임 아이디 비밀번호를 4자리 ‘소수’로 정해놓았다. 어느 날 창영이는 친한 친구와 대화를 나누었는데: “이제 슬슬 비번 바꿀 때도 됐잖아” “응 지금

www.acmicpc.net

문제

소수를 유난히도 좋아하는 창영이는 게임 아이디 비밀번호를 4자리 ‘소수’로 정해놓았다. 어느 날 창영이는 친한 친구와 대화를 나누었는데:

  • “이제 슬슬 비번 바꿀 때도 됐잖아”
  • “응 지금은 1033으로 해놨는데... 다음 소수를 무엇으로 할지 고민중이야"
  • “그럼 8179로 해”
  • “흠... 생각 좀 해볼게. 이 게임은 좀 이상해서 비밀번호를 한 번에 한 자리 밖에 못 바꾼단 말이야. 예를 들어 내가 첫 자리만 바꾸면 8033이 되니까 소수가 아니잖아. 여러 단계를 거쳐야 만들 수 있을 것 같은데... 예를 들면... 1033 1733 3733 3739 3779 8779 8179처럼 말이야.”
  • “흠...역시 소수에 미쳤군. 그럼 아예 프로그램을 짜지 그래. 네 자리 소수 두 개를 입력받아서 바꾸는데 몇 단계나 필요한지 계산하게 말야.”
  • “귀찮아”

그렇다. 그래서 여러분이 이 문제를 풀게 되었다. 입력은 항상 네 자리 소수만(1000 이상) 주어진다고 가정하자. 주어진 두 소수 A에서 B로 바꾸는 과정에서도 항상 네 자리 소수임을 유지해야 하고, ‘네 자리 수’라 하였기 때문에 0039 와 같은 1000 미만의 비밀번호는 허용되지 않는다.

입력

첫 줄에 test case의 수 T가 주어진다. 다음 T줄에 걸쳐 각 줄에 1쌍씩 네 자리 소수가 주어진다.

출력

각 test case에 대해 두 소수 사이의 변환에 필요한 최소 회수를 출력한다. 불가능한 경우 Impossible을 출력한다.

예제 입력 1

3

1033 8179

1373 8017

1033 1033

예제 출력 1

6

7

0

 

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.StringTokenizer;

class Pair {
    int now;
    int time;
    Pair(int now, int time) {
        this.now = now;
        this.time = time;
    }
}

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;

    static int ans;
    static boolean[] check = null;

    public static boolean isPrime(int num) {
        if(num == 2) return true;
        if(num == 0 || num == 1 || num % 2 == 0) return false;
        for(int i = 3; i <= Math.sqrt(num); i++) {
            if(num % i == 0) {
                return false;
            }
        }
        return true;
    }

    public static void bfs(int start, int destination) {
        Queue<Pair> que = new ArrayDeque<>();
        que.add(new Pair(start, 0));
        check[start - 1000] = true;

        while(!que.isEmpty()) {
            Pair p = que.poll();
            int now = p.now;
            int time = p.time;
            if(now == destination) {
                ans = time;
                return;
            }

            for(int i = 0; i < 4; i++) {
                for(int j = 0; j <= 9; j++) {
                    if(i == 3 && j == 0) continue;  // 천의자리에는 0이 올 수 없음. 반드시 4자리 수

                    int digit = (int)Math.pow(10, i);
                    int temp = now / (int)Math.pow(10, i) % 10;  // temp = now의 i번째 자리의 수
                    int sub = digit * temp;
                    int sum = digit * j;
                    int next = now - sub + sum;

                    if(!check[next - 1000] && isPrime(next)) {
                        que.add(new Pair(next, time + 1));
                        check[next - 1000] = true;
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());

        while(T-- > 0) {
            st = new StringTokenizer(br.readLine());
            int from = Integer.parseInt(st.nextToken());
            int to = Integer.parseInt(st.nextToken());

            check = new boolean[9000];  // 0 ~ 8999 == 1000 ~ 9999
            bfs(from, to);
            System.out.println(ans);
        }
    }
}

 

알고리즘 자체는 복잡할 게 없는 전형적인 BFS를 이용한 최단경로 문제였다.

 

수학 멍청이라서 구현에서 애를 많이 먹었다.

 

자리수 교체에 String을 사용하지 않고 int로만 처리하고 싶어서 고집을 부렸는데 막상 교체 타겟 자리수의 숫자를 어떻게 뽑아야 할 지 몰라서 애를 먹었다.

 

결국 뽑아내는법은 구글링을 해서 참고했다.

-> 

1. 뽑고싶은 자리로 나눈 몫을 구한다.

백의자리의 수를 뽑아야 한다고 할 때, 현재 수를 100으로 나눈 몫을 구하면 그 몫의 1의 자리가 내가 뽑고싶은 백의자리 숫자가 된다.

 

2. 구한 몫을 10으로 나눈 나머지를 구한다.

그걸 다시 % 10 연산을 사용해 뽑아내면 최초에 타겟한 자리의 수가 나온다.

 

 

소수 판별에 대해서는 굳이 '에라토스테네스의 체' 를 사용하지 않아도 시간초과가 발생하지는 않았다.

 

 

 

 

 

'알고리즘 문제 > 백준 온라인 저지' 카테고리의 다른 글

[BOJ] 2251 - 물통 JAVA  (0) 2021.02.12
[BOJ] 9019 - DSLR JAVA  (0) 2021.02.11
[BOJ] 1697 - 숨바꼭질 JAVA  (0) 2021.02.11
[BOJ] 10971 - 외판원 순회 2 JAVA  (0) 2021.02.11
[BOJ] 10819 - 차이를 최대로 JAVA  (0) 2021.02.10

www.acmicpc.net/problem/1697

 

1697번: 숨바꼭질

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

문제

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때 걷는다면 1초 후에 X-1 또는 X+1로 이동하게 된다. 순간이동을 하는 경우에는 1초 후에 2*X의 위치로 이동하게 된다.

수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 구하는 프로그램을 작성하시오.

입력

첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. N과 K는 정수이다.

출력

수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.

예제 입력 1

5 17

예제 출력 1

4

 

 

 

 

 

 

 

풀이 1. (틀린 코드)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static int n, k, ans;
    static boolean[] check = null;

    public static void dfs(int now, int deptNow, int destination) {
        if(deptNow > ans) {  // 최소 경로 구하는 것이므로 경로가 더 커지면 그냥 바로 나가면 된다.
            return;
        }
        if(now == destination) {
            ans = deptNow;
            return;
        }

        if(0 <= now+1 && now+1 <= 100000 && !check[now+1]) {
            check[now+1] = true;
            dfs(now + 1, deptNow + 1, destination);
        }
        if(0 <= now-1 && now-1 <= 100000 && !check[now-1]) {
            check[now-1] = true;
            dfs(now - 1, deptNow + 1, destination);
        }
        if(0 <= now*2 && now*2 <= 100000 && !check[now*2]) {
            check[now*2] = true;
            dfs(now * 2, deptNow + 1, destination);
        }
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        ans = Math.abs(n - k);
        check = new boolean[100001];

        if(0 <= n+1 && n+1 <= 100000) {
            check[n+1] = true;
            dfs(n + 1, 1, k);
        }
        if(0 <= n-1 && n-1 <= 100000) {
            check[n-1] = true;
            dfs(n - 1, 1, k);
        }
        if(0 <= n*2 && n*2 <= 100000) {
            check[n*2] = true;
            dfs(n * 2, 1, k);
        }
        System.out.println(ans);
    }
}

 

쉽게 봤는데 생각보다 애를 좀 먹었다.

 

DFS로 접근하면 StackOverflow를 맞는다.

 

최단경로를 찾자마자 바로 반환하는 방식이 아니라 모든 경로를 다 찾은 후 그 중에서 최단경로를 구하는 방식이기 때문인 것 같다.

 

DFS 코드 첫째줄에 if(deptNow > ans) return 을 두어서 줄여보고자 했으나 역부족이었다.

 

 

 

 

 

풀이 2. (정답 코드)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.StringTokenizer;

class Pair {
    int now;
    int time;
    public Pair(int now, int time) {
        this.now = now;
        this.time = time;
    }
}

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static int n, k, ans;
    static boolean[] check = null;

    public static void bfs(int start, int destination) {
        Queue<Pair> que = new ArrayDeque<>();
        que.add(new Pair(start, 0));
        check[start] = true;

        while(!que.isEmpty()) {
            Pair p = que.poll();
            int now = p.now;
            int time = p.time;

            if(now == destination) {
                ans = time;
                return;
            }

            if(0 <= now+1 && now+1 <= 100000 && !check[now+1]) {
                que.add(new Pair(now+1, time+1));
                check[now+1] = true;
            }
            if(0 <= now-1 && now-1 <= 100000 && !check[now-1]) {
                que.add(new Pair(now-1, time+1));
                check[now-1] = true;
            }
            if(0 <= now*2 && now*2 <= 100000 && !check[now*2]) {
                que.add(new Pair(now*2, time+1));
                check[now*2] = true;
            }
        }
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        check = new boolean[100001];

        bfs(n, k);
        System.out.println(ans);
    }
}

 

BFS를 사용해서 풀어야 각종 초과 에러들을 면할 수 있다.

 

목적지에 도착하자마자 바로 return하기 때문에 빠르게 해결할 수 있다.

 

 

 

www.acmicpc.net/problem/10971

 

10971번: 외판원 순회 2

첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 10) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j

www.acmicpc.net

문제

외판원 순회 문제는 영어로 Traveling Salesman problem (TSP) 라고 불리는 문제로 computer science 분야에서 가장 중요하게 취급되는 문제 중 하나이다. 여러 가지 변종 문제가 있으나, 여기서는 가장 일반적인 형태의 문제를 살펴보자.

1번부터 N번까지 번호가 매겨져 있는 도시들이 있고, 도시들 사이에는 길이 있다. (길이 없을 수도 있다) 이제 한 외판원이 어느 한 도시에서 출발해 N개의 도시를 모두 거쳐 다시 원래의 도시로 돌아오는 순회 여행 경로를 계획하려고 한다. 단, 한 번 갔던 도시로는 다시 갈 수 없다. (맨 마지막에 여행을 출발했던 도시로 돌아오는 것은 예외) 이런 여행 경로는 여러 가지가 있을 수 있는데, 가장 적은 비용을 들이는 여행 계획을 세우고자 한다.

각 도시간에 이동하는데 드는 비용은 행렬 W[i][j]형태로 주어진다. W[i][j]는 도시 i에서 도시 j로 가기 위한 비용을 나타낸다. 비용은 대칭적이지 않다. 즉, W[i][j] 는 W[j][i]와 다를 수 있다. 모든 도시간의 비용은 양의 정수이다. W[i][i]는 항상 0이다. 경우에 따라서 도시 i에서 도시 j로 갈 수 없는 경우도 있으며 이럴 경우 W[i][j]=0이라고 하자.

N과 비용 행렬이 주어졌을 때, 가장 적은 비용을 들이는 외판원의 순회 여행 경로를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 10) 다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j로 가기 위한 비용을 나타낸다.

항상 순회할 수 있는 경우만 입력으로 주어진다.

출력

첫째 줄에 외판원의 순회에 필요한 최소 비용을 출력한다.

예제 입력 1

4

0 10 15 20

5 0 9 10

6 13 0 12

8 8 9 0

예제 출력 1

35

 

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    static BufferedReader br = null;
    static StringTokenizer st = null;

    static int[][] map = null;
    static int[] path = null;
    static boolean[] check = null;

    static int n, ans = 10000000;  // 초기값 1천만

    public static int calculate() {
        int result = 0;
        for(int i = 0; i < n; i++) {
            int from = path[i];
            int to = path[i+1];
            result += map[from][to];
        }
        return result;
    }

    public static void dfs(int start, int now, int deptNow, int dept) {
        if(deptNow == dept) {
            if(map[now][start] != 0) {
                path[deptNow] = start;
                ans = Math.min(ans, calculate());
            }
            return;
        }

        for(int i = 0; i < n; i++) {
            if(!check[i] && map[now][i] != 0) {
                path[deptNow] = i;
                check[i] = true;
                dfs(start, i, deptNow + 1, dept);
                check[i] = false;
            }
        }
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
        map = new int[n][n];
        path = new int[n + 1];
        check = new boolean[n];

        for(int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            for(int j = 0; j < n; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        for(int i = 0; i < n; i++) {
            path[0] = i;
            check[i] = true;
            dfs(i, i, 1, n);
            check[i] = false;
        }
        System.out.println(ans);
    }
}

 

백트래킹을 이용한 완전탐색 문제.

 

모든 조합을 구하여 최소 경로를 찾는다.

www.acmicpc.net/problem/10819

 

10819번: 차이를 최대로

첫째 줄에 N (3 ≤ N ≤ 8)이 주어진다. 둘째 줄에는 배열 A에 들어있는 정수가 주어진다. 배열에 들어있는 정수는 -100보다 크거나 같고, 100보다 작거나 같다.

www.acmicpc.net

문제

N개의 정수로 이루어진 배열 A가 주어진다. 이때, 배열에 들어있는 정수의 순서를 적절히 바꿔서 다음 식의 최댓값을 구하는 프로그램을 작성하시오.

|A[0] - A[1]| + |A[1] - A[2]| + ... + |A[N-2] - A[N-1]|

입력

첫째 줄에 N (3 ≤ N ≤ 8)이 주어진다. 둘째 줄에는 배열 A에 들어있는 정수가 주어진다. 배열에 들어있는 정수는 -100보다 크거나 같고, 100보다 작거나 같다.

출력

첫째 줄에 배열에 들어있는 수의 순서를 적절히 바꿔서 얻을 수 있는 식의 최댓값을 출력한다.

예제 입력 1

6

20 1 15 8 4 10

예제 출력 1

62

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    static BufferedReader br = null;
    static StringTokenizer st = null;
    static int n, ans;
    static int[] arr = null;
    static int[] temp = null;
    static boolean[] check = null;

    public static int calculate() {
        int result = 0;
        for(int i = 0; i < n - 1; i++) {
            result += Math.abs(temp[i] - temp[i+1]);
        }
        return result;
    }

    public static void dfs(int deptNow, int dept) {
        if(deptNow == dept) {
            ans = Math.max(ans, calculate());
            return;
        }

        for(int i = 0; i < n; i++) {
            if(!check[i]) {
                temp[deptNow] = arr[i];
                check[i] = true;
                dfs(deptNow + 1, dept);
                check[i] = false;
            }
        }
    }

    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
        arr = new int[n];
        temp = new int[n];
        check = new boolean[n];

        st = new StringTokenizer(br.readLine());
        for(int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }

        for(int i = 0; i < n; i++) {
            temp[0] = arr[i];
            check[i] = true;
            dfs(1, n);
            check[i] = false;
        }
        System.out.println(ans);
    }
}

 

백트래킹을 통해 모든 조합을 구한다.

 

N의 최대값이 8이고 8! (= 40320) 안에 해결 가능하므로 브루트포스 사용 가능.

www.acmicpc.net/problem/1107

 

1107번: 리모컨

첫째 줄에 수빈이가 이동하려고 하는 채널 N (0 ≤ N ≤ 500,000)이 주어진다.  둘째 줄에는 고장난 버튼의 개수 M (0 ≤ M ≤ 10)이 주어진다. 고장난 버튼이 있는 경우에는 셋째 줄에는 고장난 버튼

www.acmicpc.net

문제

수빈이는 TV를 보고 있다. 수빈이는 채널을 돌리려고 했지만, 버튼을 너무 세게 누르는 바람에, 일부 숫자 버튼이 고장났다.

리모컨에는 버튼이 0부터 9까지 숫자, +와 -가 있다. +를 누르면 현재 보고있는 채널에서 +1된 채널로 이동하고, -를 누르면 -1된 채널로 이동한다. 채널 0에서 -를 누른 경우에는 채널이 변하지 않고, 채널은 무한대 만큼 있다.

수빈이가 지금 이동하려고 하는 채널은 N이다. 어떤 버튼이 고장났는지 주어졌을 때, 채널 N으로 이동하기 위해서 버튼을 최소 몇 번 눌러야하는지 구하는 프로그램을 작성하시오. 

수빈이가 지금 보고 있는 채널은 100번이다.

입력

첫째 줄에 수빈이가 이동하려고 하는 채널 N (0 ≤ N ≤ 500,000)이 주어진다.  둘째 줄에는 고장난 버튼의 개수 M (0 ≤ M ≤ 10)이 주어진다. 고장난 버튼이 있는 경우에는 셋째 줄에는 고장난 버튼이 주어지며, 같은 버튼이 여러 번 주어지는 경우는 없다.

출력

첫째 줄에 채널 N으로 이동하기 위해 버튼을 최소 몇 번 눌러야 하는지를 출력한다.

예제 입력 1

5457

3

6 7 8

예제 출력 1

6

예제 입력 2

100

5

0 1 2 3 4

예제 출력 2

0

예제 입력 3

500000

8

0 2 3 4 6 7 8 9

예제 출력 3 복사

11117

 

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = null;

        int n = Integer.parseInt(br.readLine());  // 목표 채널
        int m = Integer.parseInt(br.readLine());  // 망가진 버튼 수
        boolean[] isBroken = new boolean[10];  // 버튼 고장 여부

        if(m != 0) {
            st = new StringTokenizer(br.readLine());
        }
        for(int i = 0; i < m; i++) {
            int brokenBtn = Integer.parseInt(st.nextToken());
            isBroken[brokenBtn] = true;
        }

        if(n == 100) {  // 예외처리
            System.out.println(0);
            return;
        }

        int ans = Math.abs(n - 100);  // 초기값은 숫자 없이 + or - 이동
        for(int i = 0; i <= 1000000; i++) {  // i까지 숫자버튼으로 이동 후 +,- 버튼으로 이동하는 수
            String strChan = String.valueOf(i);

            // 숫자 버튼으로 이동 가능한지 체크
            boolean isPossible = true;
            for(int j = 0; j < strChan.length(); j++) {
                int btn = strChan.charAt(j) - '0';
                if(isBroken[btn]) {
                    isPossible = false;
                    break;  // 고장난 버튼이 있으면 다이렉트로 접근 불가능
                }
            }

            if(isPossible) {
                int cnt = strChan.length() + Math.abs(i - n);  // 숫자 이동 후 +,- 이동
                ans = Math.min(ans, cnt);
            }
        }
        System.out.println(ans);
    }
}

 

예외처리 때문에 한참을 해맸다.

M의 최소값이 0인데 M이 0일 때도 고장난 버튼에 대한 입력을 받으려고 해서 NullPointer 에러가 발생했었다.

 

초기값은 100에서 + or - 만을 사용해서 갈 수 있는 횟수로 둔다.

 

그 후 1~1,000,000에 대해 숫자버튼 이동 후 + or - 로 이동한 수를 모두 구해가며 최소값을 찾는다. (이 부분이 브루트 포스)

 

백만까지 검사하는 이유? 

-> N의 최대값 50만에 대해서 1~50만, 100만~50만 양 방향을 모두 고려해야 함

 

 

 

www.acmicpc.net/problem/1476

 

1476번: 날짜 계산

준규가 사는 나라는 우리가 사용하는 연도와 다른 방식을 이용한다. 준규가 사는 나라에서는 수 3개를 이용해서 연도를 나타낸다. 각각의 수는 지구, 태양, 그리고 달을 나타낸다. 지구를 나타

www.acmicpc.net

문제

준규가 사는 나라는 우리가 사용하는 연도와 다른 방식을 이용한다. 준규가 사는 나라에서는 수 3개를 이용해서 연도를 나타낸다. 각각의 수는 지구, 태양, 그리고 달을 나타낸다.

지구를 나타내는 수를 E, 태양을 나타내는 수를 S, 달을 나타내는 수를 M이라고 했을 때, 이 세 수는 서로 다른 범위를 가진다. (1 ≤ E ≤ 15, 1 ≤ S ≤ 28, 1 ≤ M ≤ 19)

우리가 알고있는 1년은 준규가 살고있는 나라에서는 1 1 1로 나타낼 수 있다. 1년이 지날 때마다, 세 수는 모두 1씩 증가한다. 만약, 어떤 수가 범위를 넘어가는 경우에는 1이 된다.

예를 들어, 15년은 15 15 15로 나타낼 수 있다. 하지만, 1년이 지나서 16년이 되면 16 16 16이 아니라 1 16 16이 된다. 이유는 1 ≤ E ≤ 15 라서 범위를 넘어가기 때문이다.

E, S, M이 주어졌고, 1년이 준규가 사는 나라에서 1 1 1일때, 준규가 사는 나라에서 E S M이 우리가 알고 있는 연도로 몇 년인지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 세 수 E, S, M이 주어진다. 문제에 나와있는 범위를 지키는 입력만 주어진다.

출력

첫째 줄에 E S M으로 표시되는 가장 빠른 연도를 출력한다. 1 1 1은 항상 1이기 때문에, 정답이 음수가 나오는 경우는 없다.

예제 입력 1

1 16 16

예제 출력 1

16

예제 입력 2

1 1 1

예제 출력 2

1

예제 입력 3

1 2 3

예제 출력 3

5266

예제 입력 4

15 28 19

예제 출력 4

7980

 

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int[] arr = new int[3];  // E, S, M
        arr[0] = Integer.parseInt(st.nextToken());
        arr[1] = Integer.parseInt(st.nextToken());
        arr[2] = Integer.parseInt(st.nextToken());

        int ans = 1;
        int e = 1, s = 1, m = 1;
        while(!(e == arr[0] && s == arr[1] && m == arr[2])) {
            e += 1;
            s += 1;
            m += 1;
            ans += 1;
            if(e == 16) e = 1;
            if(s == 29) s = 1;
            if(m == 20) m = 1;
        }
        System.out.println(ans);
    }
}

 

브루트 포스로 해결.

 

 

 

'알고리즘 문제 > 백준 온라인 저지' 카테고리의 다른 글

[BOJ] 10819 - 차이를 최대로 JAVA  (0) 2021.02.10
[BOJ] 1107 - 리모컨 JAVA  (0) 2021.02.10
[BOJ] 1744 - 수 묶기 JAVA  (0) 2021.02.10
[BOJ] 11399 - ATM JAVA  (0) 2021.02.10
[BOJ] 1931 - 회의실 배정 JAVA  (0) 2021.02.10

www.acmicpc.net/problem/1744

 

1744번: 수 묶기

길이가 N인 수열이 주어졌을 때, 그 수열의 합을 구하려고 한다. 하지만, 그냥 그 수열의 합을 모두 더해서 구하는 것이 아니라, 수열의 두 수를 묶으려고 한다. 어떤 수를 묶으려고 할 때, 위치에

www.acmicpc.net

문제

길이가 N인 수열이 주어졌을 때, 그 수열의 합을 구하려고 한다. 하지만, 그냥 그 수열의 합을 모두 더해서 구하는 것이 아니라, 수열의 두 수를 묶으려고 한다. 어떤 수를 묶으려고 할 때, 위치에 상관없이 묶을 수 있다. 하지만, 같은 위치에 있는 수(자기 자신)를 묶는 것은 불가능하다. 그리고 어떤 수를 묶게 되면, 수열의 합을 구할 때 묶은 수는 서로 곱한 후에 더한다.

예를 들면, 어떤 수열이 {0, 1, 2, 4, 3, 5}일 때, 그냥 이 수열의 합을 구하면 0+1+2+4+3+5 = 15이다. 하지만, 2와 3을 묶고, 4와 5를 묶게 되면, 0+1+(2*3)+(4*5) = 27이 되어 최대가 된다.

수열의 모든 수는 단 한번만 묶거나, 아니면 묶지 않아야한다.

수열이 주어졌을 때, 수열의 각 수를 적절히 묶었을 때, 그 합이 최대가 되게 하는 프로그램을 작성하시오.

입력

첫째 줄에 수열의 크기 N이 주어진다. N은 10,000보다 작은 자연수이다. 둘째 줄부터 N개의 줄에, 수열의 각 수가 주어진다. 수열의 수는 -10,000보다 크거나 같고, 10,000보다 작거나 같은 정수이다.

출력

수를 합이 최대가 나오게 묶었을 때 합을 출력한다. 정답은 항상 231보다 작다.

예제 입력 1

4

-1

2

1

3

예제 출력 1

6

 

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());

        ArrayList<Integer> positive = new ArrayList<>();
        ArrayList<Integer> negative = new ArrayList<>();
        boolean hasZero = false;
        int oneCnt = 0;
        for(int i = 0; i < n; i++) {
            int input = Integer.parseInt(br.readLine());
            if(input > 0) {
                if(input == 1) {  // 1은 곱하면 오리혀 손해이므로 따로 개수를 세서 더해준다
                    oneCnt += 1;
                }else {
                    positive.add(input);
                }
            }else if(input < 0) {
                negative.add(input);
            }else {
                hasZero = true;
            }
        }

        // 양수, 음수 각자 절대값의 크기로 내림차순
        Collections.sort(positive);
        Collections.reverse(positive);
        Collections.sort(negative);

        int ans = oneCnt;
        int size = positive.size();
        for(int i = 0; i < size; i+=2) {  // positive
            if(i == size - 1) {  // positive가 홀수개이면 절대값이 가장 작은 것은 그냥 더해줌
                ans += positive.get(i);
            }else {
                ans += positive.get(i) * positive.get(i+1);
            }
        }

        size = negative.size();
        for(int i = 0; i < size; i+=2) {  // negative
            if(i == size - 1) {  // negative가 홀수개이면 절대값이 가장 작은 음수를 0으로 상쇄시킬 수 있는지 확인
                if(!hasZero) {  // 음수를 상쇄시킬 0이 없으면 그냥 음수 더하기
                    ans += negative.get(i);
                }
            }else {
                ans += negative.get(i) * negative.get(i+1);
            }
        }
        System.out.println(ans);
    }
}

 

최대의 합을 만들어내기 위해 양수, 음수, 0을 모두 따로 생각해야 한다.

 

1. 양수일 때

내림차순 정렬하여 절대값이 큰 것 끼리 곱해주면 된다.

홀수개라서 짝이 안 맞을 경우 마지막 원소(= 절대값이 가장 작은 원소)는 그냥 혼자 더해준다.

단, 입력이 1인 경우에는 곱하는 것이 오히려 손해가 된다. 따라서 1의 개수는 따로 세어준 다음 정답 수에 더해준다.

 

2. 음수일 때

오름차순 정렬하여 절대값이 큰 것 끼리 곱해주면 된다.

음수가 짝수개일 경우 모두 짝을 지어 음의 값을 상쇄시킬 수 있다.

만약 홀수개라면 마지막 남은 음수는 0과 묶어서 그 값을 상쇄시켜야 한다. 함께 묶을 0이 없다면 어쩔 수 없이 음의 값을 더해주어야 한다.

 

3. 0일 때

어차피 0은 묶어서 더하든 그냥 더하든 0이다. 총합에 영향을 미치지 않는다.

마지막 하나 남은 음수의 값을 상쇄시켜줄 0이 있는지 없는지만 확인하면 되기 때문에 boolean으로 존재 유무만 체크해주면 된다.

 

 

 

'알고리즘 문제 > 백준 온라인 저지' 카테고리의 다른 글

[BOJ] 1107 - 리모컨 JAVA  (0) 2021.02.10
[BOJ] 1476 - 날짜 계산 JAVA  (0) 2021.02.10
[BOJ] 11399 - ATM JAVA  (0) 2021.02.10
[BOJ] 1931 - 회의실 배정 JAVA  (0) 2021.02.10
[BOJ] 1783 - 병든 나이트 JAVA  (0) 2021.02.09

www.acmicpc.net/problem/11399

 

11399번: ATM

첫째 줄에 사람의 수 N(1 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 각 사람이 돈을 인출하는데 걸리는 시간 Pi가 주어진다. (1 ≤ Pi ≤ 1,000)

www.acmicpc.net

 

문제

인하은행에는 ATM이 1대밖에 없다. 지금 이 ATM앞에 N명의 사람들이 줄을 서있다. 사람은 1번부터 N번까지 번호가 매겨져 있으며, i번 사람이 돈을 인출하는데 걸리는 시간은 Pi분이다.

사람들이 줄을 서는 순서에 따라서, 돈을 인출하는데 필요한 시간의 합이 달라지게 된다. 예를 들어, 총 5명이 있고, P1 = 3, P2 = 1, P3 = 4, P4 = 3, P5 = 2 인 경우를 생각해보자. [1, 2, 3, 4, 5] 순서로 줄을 선다면, 1번 사람은 3분만에 돈을 뽑을 수 있다. 2번 사람은 1번 사람이 돈을 뽑을 때 까지 기다려야 하기 때문에, 3+1 = 4분이 걸리게 된다. 3번 사람은 1번, 2번 사람이 돈을 뽑을 때까지 기다려야 하기 때문에, 총 3+1+4 = 8분이 필요하게 된다. 4번 사람은 3+1+4+3 = 11분, 5번 사람은 3+1+4+3+2 = 13분이 걸리게 된다. 이 경우에 각 사람이 돈을 인출하는데 필요한 시간의 합은 3+4+8+11+13 = 39분이 된다.

줄을 [2, 5, 1, 4, 3] 순서로 줄을 서면, 2번 사람은 1분만에, 5번 사람은 1+2 = 3분, 1번 사람은 1+2+3 = 6분, 4번 사람은 1+2+3+3 = 9분, 3번 사람은 1+2+3+3+4 = 13분이 걸리게 된다. 각 사람이 돈을 인출하는데 필요한 시간의 합은 1+3+6+9+13 = 32분이다. 이 방법보다 더 필요한 시간의 합을 최소로 만들 수는 없다.

줄을 서 있는 사람의 수 N과 각 사람이 돈을 인출하는데 걸리는 시간 Pi가 주어졌을 때, 각 사람이 돈을 인출하는데 필요한 시간의 합의 최솟값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 사람의 수 N(1 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 각 사람이 돈을 인출하는데 걸리는 시간 Pi가 주어진다. (1 ≤ Pi ≤ 1,000)

출력

첫째 줄에 각 사람이 돈을 인출하는데 필요한 시간의 합의 최솟값을 출력한다.

예제 입력 1

5

3 1 4 3 2

예제 출력 1

32

 

 

 

 

 

 

 

 

풀이 .

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int[] arr = new int[n];

        st = new StringTokenizer(br.readLine());
        for(int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(st.nextToken());
        }
        Arrays.sort(arr);

        int ans = 0;
        for(int i = 0; i < n; i++) {
            for(int j = i; j < n; j++) {
                ans += arr[i];
            }
        }
        System.out.println(ans);
    }
}

 

먼저 오름차순 정렬을 한다.

 

앞의 사람이 돈을 뽑는 대기시간은 뒤의 사람들도 함께 대기하기 때문에 뒤의 사람들에게도 전부 더해주면 된다.

 

 

 

'알고리즘 문제 > 백준 온라인 저지' 카테고리의 다른 글

[BOJ] 1476 - 날짜 계산 JAVA  (0) 2021.02.10
[BOJ] 1744 - 수 묶기 JAVA  (0) 2021.02.10
[BOJ] 1931 - 회의실 배정 JAVA  (0) 2021.02.10
[BOJ] 1783 - 병든 나이트 JAVA  (0) 2021.02.09
[BOJ] 10610 - 30 JAVA  (0) 2021.02.09

+ Recent posts