Java/코딩테스트

백준 2636, 1339, 2110

Bubbles 2023. 9. 5. 19:14

🧀 백준 2636 : 치즈

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

 

2636번: 치즈

아래 <그림 1>과 같이 정사각형 칸들로 이루어진 사각형 모양의 판이 있고, 그 위에 얇은 치즈(회색으로 표시된 부분)가 놓여 있다. 판의 가장자리(<그림 1>에서 네모 칸에 X친 부분)에는 치즈가 놓

www.acmicpc.net

 

🧀 공기를 기준으로 탐색 수행, 치즈를 만나면 해당 치즈를 녹이고 방문처리, 공기를 만나면 해당 칸을 탐색후보에 넣고 수행한다.

🧀 아이디어는 나름 금방 생각했는데 생각보다 구현이 오래 걸렸다. 

🧀 재귀말고 stack 방식으로 구현해서 풀었다. 

🧀 tmi. 카페에서 이거 풀었는데 치즈가 먹고 싶었다. 하지만 그 카페는 치즈가 들어간 것을 팔지 않았다. 

 

🧀 전체 코드

import java.util.*;
import java.io.*;
public class p2636 {
    private static int row, col;
    private static int[][] map;
    private static boolean[][] visited;
    private static int[] dirX = { -1, 1, 0, 0 };
    private static int[] dirY = { 0, 0, -1, 1 };
    private static int cheese = 0;
    private static int temp;
    private static int time = 0;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        row = Integer.parseInt(st.nextToken());
        col = Integer.parseInt(st.nextToken());
        map = new int[row][col];
        visited = new boolean[row][col];

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

        while (cheese > 0) {
            temp = cheese;
            find();
            visited = new boolean[row][col];
            time++;
        }

        System.out.println(time);
        System.out.println(temp);
    }

    private static void find() {
        Stack<int[]> stack = new Stack<>();
        stack.push(new int[] {0, 0});

        while (!stack.isEmpty()) {
            int[] pop = stack.pop();
            visited[pop[0]][pop[1]] = true;
            for (int i = 0; i < 4; i++) {
                int nextX = pop[0] + dirX[i];
                int nextY = pop[1] + dirY[i];

                if (!isValid(nextX,nextY)) {
                    continue;
                }

                if (visited[nextX][nextY]) {
                    continue;
                }

                if (map[nextX][nextY] == 0) {
                    stack.push(new int[] {nextX, nextY});
                } else if (map[nextX][nextY] == 1) {
                    map[nextX][nextY]--;
                    cheese--;
                    visited[nextX][nextY] = true;
                }
            }

        }
    }

    private static boolean isValid(int x, int y) {
        if (x < 0 || x >= row || y < 0 || y >= col) {
            return false;
        }
        return true;
    }

}

 


🗒 백준 1339 : 단어 수학 

 

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

 

1339번: 단어 수학

첫째 줄에 단어의 개수 N(1 ≤ N ≤ 10)이 주어진다. 둘째 줄부터 N개의 줄에 단어가 한 줄에 하나씩 주어진다. 단어는 알파벳 대문자로만 이루어져있다. 모든 단어에 포함되어 있는 알파벳은 최대

www.acmicpc.net

🗒 처음엔 문자의 빈도수 + 최대 자릿수를 저장해둔 다음 최대 자릿수 -> 빈도수 순으로 큰 값을 배정하도록 생각을 했었다.

🗒 그런데 다음과 같은 상황에선 반례가 된다. 처음 내가 생각했던 로직대로면 A에 9가 배정되어 1771이 답으로 나오는데, B에 9가 배정되는 것이 1772로 더 최대값이다. (계속 틀리길래 질문게시판에서 반례를 찾아봤는데, 이런 경우도 있다)

10
ABB
BC
BC
BC
BC
BC
BC
BC
BC
BC

🗒 그러므로, 그냥 알파벳 가중치를 담는 배열을 만들고, 문자열 하나 읽을때마다 해당 자릿수에 해당하는 사이즈만큼 배열 위치에 가중치를 넣어준다. 

🗒 ex ) ABBB : A 자리엔 1000, B자리엔 111 

🗒 그 다음 가중치 내림차순으로 배열을 탐색하면서 9 ~ 0까지 곱해서 계산해주고, 정답에 더해주면 된다. 

 

 

🗒 전체 코드

import java.util.*;
import java.io.*;
public class p1339 {
    private static int[] weight;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int index = 9;
        int sum = 0;
        weight = new int[26];

        for (int i = 0; i < n; i++) {
            calculate(br.readLine());
        }

        Arrays.sort(weight);

        for (int i = 25; i >= 0 && index >= 0; i--) {
            sum += (weight[i] * index);
            index--;
        }

        System.out.println(sum);
    }

    private static void calculate(String str) {
        int len = str.length();
        for (int i = 0; i < len; i++) {
            int index = str.charAt(i) - 65;
            weight[index] += Math.pow(10, len - i - 1);
        }
    }
}

 


📡백준 2110 : 공유기 설치

 

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

 

2110번: 공유기 설치

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가

www.acmicpc.net

 

 

📡 공유기 간 최소 거리에 대해 설치 가능한 공유기 => 최소 거리가 X라면, 공유기 C대 설치 가능한가? 이렇게 바꿔서 생각 

📡 최소거리를 계속 계산해나가며 공유기 설치 가능하면 최소거리를 늘리고(아래 코드에서 mid 값이 최소 거리 의미, left를 mid + 1로 만든다.) , 설치 불가능하면 최소거리를 줄이는 방식으로 탐색한다. 

📡 이분 탐색을 활용하는 문제

 

📡 전체 코드 

import java.util.*;
import java.io.*;
public class p2110 {
    private static int house, wifi;
    private static int[] housePos;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        house = Integer.parseInt(st.nextToken());
        wifi = Integer.parseInt(st.nextToken());

        housePos = new int[house];
        for (int i = 0; i < house; i++) {
            housePos[i] = Integer.parseInt(br.readLine());
        }
        Arrays.sort(housePos);

        int left = 1;
        int right = housePos[house-1] - housePos[0] + 1;

        while (left < right) {
            int mid = (left + right) / 2;
            int count = calculate(mid);
            if (count >= wifi) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }

        System.out.println(left-1);

    }

    private static int calculate(int minDis) {
        int count = 1;
        int before = housePos[0];
        for (int i = 1; i < house; i++) {
            if (before + minDis <= housePos[i]) {
                before = housePos[i];
                count++;
            }
        }
        return count;
    }
}