ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 2140, 28303, 2258
    Java/코딩테스트 2023. 8. 22. 16:17

    백준 2140 지뢰찾기  💣 

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

     

    2140번: 지뢰찾기

    지뢰찾기는 N×N에서 이뤄지는 게임이다. 보드의 곳곳에는 몇 개의 지뢰가 숨겨져 있고, 지뢰가 없는 칸에는 그 칸과 인접(상하좌우 및 대각선)해 있는 8개의 칸들에 몇 개의 지뢰가 숨겨져 있는

    www.acmicpc.net

     

    💣 테두리에 인접한 영역만 직접 계산하고, 나머지 가운데 영역들은 모두 지뢰가 있다고 가정해서 지뢰의 최대 개수를 계산한다. 

    💣 그리디, 구현 문제로 분류되어 있다. 아래 그림의 분홍 형광펜 영역 기준 8방향을 탐색하는 Around함수, 그리고 Around 결과 따라 count를 감소시킬지 / 주변 숫자를 1씩 감소시킬지를 결정한다.

    💣 나머진 아래 그림 참고 

    💣 코드

    import java.io.*;
    public class p2140 {
        private static int[][] map;
        private static int[] dirX = { 0, -1, -1, -1, 0, 1, 1, 1};
        private static int[] dirY = { -1, -1, 0, 1, 1, 1, 0, -1};
        private static int n;
        public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            n = Integer.parseInt(br.readLine());
            if (n <= 2) {
                System.out.println(0);
                return;
            }
            map = new int[n][n];
            int count = (n-2)*(n-2);
    
    
            for(int i = 0; i < n; i++) {
                String temp = br.readLine();
                String[] split = temp.split("");
                for (int j = 0; j < n; j++) {
                    if (split[j].equals("#")) {
                        map[i][j] = Integer.MIN_VALUE;
                    } else {
                        map[i][j] = Integer.parseInt(split[j]);
                    }
                }
            }
    
    
            for (int i = 1; i < n-1; i++) {
                for (int j = 1; j < n-1; j++) {
                    if (i == 1 || i == n-2 || j == 1 || j == n-2) {
                        if (Around(i, j)) {
                            Delete(i, j);
                        } else { // 주변에 0이 있다는 뜻이니 무조건 그 칸은 지뢰후보 제외
                            count--;
                        }
                    }
                }
            }
            System.out.println(count);
    
        }
    
        private static void Delete(int x, int y) {
            for (int i = 0; i < 8; i++) {
                int nextX = x + dirX[i];
                int nextY = y + dirY[i];
    
                if (!isValid(nextX, nextY)) {
                    continue;
                }
    
                if (map[nextX][nextY] >= 0) {
                    map[nextX][nextY]--;
                }
    
            }
        }
        private static boolean Around(int x, int y) {
    
            for (int i = 0; i < 8; i++) {
                int nextX = x + dirX[i];
                int nextY = y + dirY[i];
    
                if (!isValid(nextX, nextY)) {
                    continue;
                }
    
                if (map[nextX][nextY] == 0) {
                    return false;
                }
    
            }
            return true;
        }
    
        private static boolean isValid (int x, int y) {
            if (x < 0 || x > n-1 || y < 0 || y > n-1) {
                return false;
            }
            return true;
        }
    }

     

     


     

    백준 28303 자석 🧲

     

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

     

    28303번: 자석

    예제 1의 경우 N극이 3번 칸에 놓이고 S극이 5번 칸에 놓이도록 자석을 설치할 때 1번 현상으로 $a_3=22$의 에너지가 충전되며, 2번 현상으로 $a_5=4$의 에너지가 소모되고, 3번 현상으로 $(5-3)\times 2=4$

    www.acmicpc.net

    🧲 누적합 문제이다.... 무지성으로 풀다가 메모리 초과와 시간 초과를 번갈아 만날 수 있는 문제... 거의 안 풀어본 문제 유형이었는데 출처를 보니 알고리즘 대회문제였다. 동적 계획법으로 시작해서 누적합으로 끝난... 

    🧲 문제에서 주어진 공식을 일반화 해서 식을 세운다. 

    En - Es - (N index - S index) * K
    = En - Es - (N index * K - S index * K)
    = En - Es - N index * K + S index * K
    = (En - N index * K) - (Es - S index * K)

     

    🧲 에너지를 최대로 만들 수 있는 값을 계산하면 된다. (여기서 착각한게, 절대값의 최대를 계산하는게 아니다. -건 +건 다양한 변화량들 중 가장 큰 값을 찾는 문제이다. ) 이 에너지에는 아래와 같은 요소가 영향을 미친다. 

    • N극 에너지는 최대한 크게
    • S극 에너지는 최대한 작게
    • N극과 S극의 인덱스 차이 작게 (자석 길이 짧게)

    따라서, 위 공식에서 En - N index * K 는 최대한 크게, Es - S index * K는 최대한 작게 만들어야 한다. 

    Es - S index * K = left 로 정의하고 문제를 풀었다. 

     

    🧲 풀이과정 첨부 

     

    🧲 for문 2중으로 돌리면 시간초과가 난다. 그러므로 for 문 하나에 해결해나가는게 키 포인트

    • index 가 1부터 시작하는데, 얘는 N극과 S극의 인덱스 차이와 같다.
    • index를 이동하면서 에너지 총량을 Max로 갱신하는 작업 +  left는 위에서 설명했듯 최소로 만들어줘야 하므로 left를 Min으로 갱신하는 작업이 필요하다. 
    • 그리고 N-S 뒤집을 수도 있다. 그냥 편하게 reverse 배열에 에너지 반대로 넣은 다음 동일 로직으로 계산했다. 이정도는 메모리 제한에 걸리지 않았다.

     

    🧲 전체 코드 

    import java.io.*;
    import java.util.*;
    public class p28303 {
        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 k = Integer.parseInt(st.nextToken());
            long answer = Long.MIN_VALUE;
            long[] num = new long[n];
            long[] reverse = new long[n];
    
            st = new StringTokenizer(br.readLine());
            for (int i = 0; i < n; i++) {
                num[i] = Long.parseLong(st.nextToken());
                reverse[n-i-1] = num[i];
            }
    
    
            long left = num[0];
            for (int index = 1; index < n; index++) {
                // left가 S극을 의미, 가장 작아야만 에너지가 제일 크게 나옴
                answer = Math.max(answer, num[index] - ((long) index * k) - left);
                left = Math.min(left, num[index] - ((long) index * k));
            }
    
            left = reverse[0];
            for (int index = 1; index < n; index++) {
                answer = Math.max(answer, reverse[index] - ((long) index * k) - left);
                left = Math.min(left, reverse[index] - ((long) index * k));
            }
    
            System.out.println(answer);
        }
    }

     

     

     


    백준 2258 정육점 🥩

     

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

     

    2258번: 정육점

    첫째 줄에 두 정수 N(1 ≤ N ≤ 100,000), M(1 ≤ M ≤ 2,147,483,647)이 주어진다. N은 덩어리의 개수를 의미하고, M은 은혜가 필요한 고기의 양이다. 다음 N개의 줄에는 각 고기 덩어리의 무게와 가격을 나

    www.acmicpc.net

     

    🥩 Greedy, "가격은 적게, 양은 많게"가 이 문제가 요구하는 욕심(?)이다. 이를 기준으로 🥩를 우선순위큐에 넣기

    🥩 주의사항 : 이 문제에서 가격은 같은데 양이 다른 고기가 있을 수도 있다.

    • 예를 들어 가격이 2인 고기가 양이 2, 3, 4인 채로 포장되어있다 하자.
    • 가격이 2이고 양이 4로 가장 많은 고기를 산다.
    • 그치만 양이 2, 3인 애들은 가격이 더 적은게 아니기 때문에 담을 수 없다. 
    • 2,3인 애들을 가져가려면 각각 가격만큼 추가로 지불해야한다. 이 조건을 빼먹지 말자. 

    🥩 각 경우마다 총 지불할 금액, 고기총량, 고기들 중 최대 가격을 계산해주면 된다. 

    🥩 고기 총량이 필요한 양을 넘긴 시점부터 Math.min으로 갱신해주면 된다. 

     

    🥩 추가 설명 : 여기 있는 예제는 문제 예제 말고 일부러 같은 가격에 양 다른 고기를 넣어봤다. 

     

    🥩 전체 코드

    import java.io.*;
    import java.util.*;
    public class p2258 {
        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 need = Integer.parseInt(st.nextToken());
            int money = 0; // 사용 금액
            int maxMoney = 0;
            int amount = 0;
            int answer = Integer.MAX_VALUE;
            boolean isSuccess = false;
    
            PriorityQueue<Meat> pq = new PriorityQueue<>();
            for (int i = 0; i < n; i++) {
                st = new StringTokenizer(br.readLine());
                int size = Integer.parseInt(st.nextToken());
                int price = Integer.parseInt(st.nextToken());
                pq.add(new Meat(size, price));
            }
    
            while (!pq.isEmpty()) {
                Meat poll = pq.poll();
                if (maxMoney < poll.price) {
                    maxMoney = poll.price;
                    money = poll.price;
                } else if (maxMoney == poll.price) {
                    money += poll.price;
                }
                amount += poll.size;
                if (amount >= need) {
                    answer = Math.min(answer, money);
                    isSuccess = true;
                }
            }
    
            if (isSuccess) {
                System.out.println(answer);
            } else {
                System.out.println(-1);
            }
    
        }
    
        private static class Meat implements Comparable<Meat> {
            int size;
            int price;
    
            Meat(int size, int price) {
                this.size = size;
                this.price = price;
            }
    
            @Override
            public int compareTo(Meat o) {
                if (this.price == o.price) {
                    return o.size - this.size;
                }
                return this.price - o.price;
            }
        }
    }

     

     

     

     

     

     

     

     

     

     

     

     

    'Java > 코딩테스트' 카테고리의 다른 글

    백준 2636, 1339, 2110  (0) 2023.09.05
    백준 3055, 1600, 7576  (0) 2023.08.30
    백준 2240  (0) 2023.08.15
    백준 2293  (0) 2023.08.15
    백준 2206, 14442  (0) 2023.08.13
Designed by Tistory.