문제 - https://www.acmicpc.net/problem/11438

 

11438번: LCA 2

첫째 줄에 노드의 개수 N이 주어지고, 다음 N-1개 줄에는 트리 상에서 연결된 두 정점이 주어진다. 그 다음 줄에는 가장 가까운 공통 조상을 알고싶은 쌍의 개수 M이 주어지고, 다음 M개 줄에는 정

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {

    static BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw= new BufferedWriter(new OutputStreamWriter(System.out));
    static StringBuilder sb = new StringBuilder();
    static StringTokenizer st;

    static int N, M, K;
    static int[] depth;
    static int[][] arr;
    static ArrayList<Integer>[] tree;

    public static void main(String[] args) throws Exception {

        N = Integer.parseInt(br.readLine());

        depth = new int[N+1];
        tree = new ArrayList[N+1];
        while(Math.pow(2, K)<=N)
            K++;
        arr = new int[N+1][K]; // arr[i][j] : i번째 노드의 2^j번째 부모

        for (int i = 0; i < N-1; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            if (tree[a]==null)
                tree[a] = new ArrayList<>();
            if (tree[b]==null)
                tree[b] = new ArrayList<>();
            tree[a].add(b);
            tree[b].add(a);
        }

        init_dep(1, 1); // init_dep(a, b) -> a번째 노드의 depth를 b로 만듬
        for (int k = 1; k < K; k++) {
            for (int v = 1; v <= N; v++) {
                arr[v][k] = arr[ arr[v][k-1] ][ k-1 ]; // "v"의 "2^k번째 부모"는 "v의 2^(k-1)번째 부모"의 "2^(k-1)번째 부모"
            }
        }

        M = Integer.parseInt(br.readLine());
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            sb.append(lca(a, b)+"\n"); // lca(a, b) -> a와 b의 최소 공통 조상 찾기
        }
        bw.write(sb.toString());

        bw.flush();
        bw.close();
        br.close();
    }
    static int lca(int a, int b){
        if(depth[a]<depth[b]){ // 무조건 a가 더 트리의 아랫쪽에 위치하도록 바꿔주기
            int tmp = a;
            a = b;
            b = tmp;
        }

        for (int i = K-1; depth[a]>depth[b]; i--) { // 제일 아랫쪽에서부터 올라오면서
            if(Math.pow(2, i) <= depth[a]-depth[b]) // 높이 차이가 2의 거듭제곱보다 작으면
                a = arr[a][i]; // 높이 맞춰주기
        }

        if (a==b) // 높이가 같은데 값도 같으면
            return a; // 바로 리턴

        for (int i = K-1; i >= 0; i--) { // 같은 높이에서 2^i만큼 높이를 올라가면서
            if(arr[a][i]!=arr[b][i]){ // 서로 다르면
                a = arr[a][i]; // 갱신
                b = arr[b][i];
            }
        }
        return arr[a][0]; // 공통조상 바로 밑이므로, 첫번째 조상 리턴
    }
    static void init_dep(int cur, int dep){
        depth[cur] = dep;
        for(int next : tree[cur]){
            if(depth[next]==0){
                arr[next][0] = cur;
                init_dep(next, dep+1);
            }
        }
    }
}

한번 풀어봤던 문제지만, 레퍼런스없이 맨땅에 구현하기는 정말 쉽지 않은 문제인것 같다.

충분한 구현계획을 잡고나서 실제 코드로 옮기는 습관을 들이자!

'공부 > algorithm' 카테고리의 다른 글

BOJ 감시 피하기(18428) - Java  (0) 2021.09.24
BOJ 탈출(3055) - Java  (0) 2021.09.15
BOJ AC(5430) - Java  (0) 2021.09.13
BOJ 고스택(3425) - Java  (0) 2021.09.13
BOJ 사다리 조작(15684) - Java  (0) 2021.09.07

문제 - https://www.acmicpc.net/problem/5430

 

5430번: AC

각 테스트 케이스에 대해서, 입력으로 주어진 정수 배열에 함수를 수행한 결과를 출력한다. 만약, 에러가 발생한 경우에는 error를 출력한다.

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {

    static BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw= new BufferedWriter(new OutputStreamWriter(System.out));
    static StringBuilder sb = new StringBuilder();

    static int T, n;
    static char[] p;
    static String[] X;

    public static void main(String[] args) throws Exception {

        T = Integer.parseInt(br.readLine()); // 테스트케이스 수
        for (int i = 0; i < T; i++) {
            p = br.readLine().toCharArray(); // 함수들 수
            n = Integer.parseInt(br.readLine());

            String input = br.readLine(); // 입력받고
            if(input.length()>2)// []보다 길면
                X = input.substring(1, input.length()-1).split(","); // 구분자를 , 로 하여 입력받고

            boolean error = false; // 에러발생여부
            boolean right = true; // 진행방향
            int l = 0;
            int r = n-1;
            for (char cmd : p){ // 함수하나씩 보면서
                if(cmd=='R') // reverse면
                    right = !right; // right 뒤집어줌
                else{ // D일때
                    if (l>r){ // 빈배열이라면
                        error = true; // 에러발생
                        sb.append("error\n");
                        break; // 즉시종료
                    }
                    if(right) // 아니면 right여부에 따라 포인터이동.
                        l++;
                    else
                        r--;
                }
            }
            if(!error) {
                sb.append("[");
                while(l<=r){
                    sb.append(X[right? l++ : r--]);
                    if(l<=r)
                        sb.append(",");
                }
                sb.append("]\n");
            }
        }
        bw.write(sb.toString());
        bw.flush();
        bw.close();
        br.close();
    }
}

Java로 처음 문자열 처리를 해봤다.

여러가지를 경험하게 되는 좋은 문제였다.

'공부 > algorithm' 카테고리의 다른 글

BOJ 탈출(3055) - Java  (0) 2021.09.15
BOJ LCA 2(11438) - Java  (0) 2021.09.13
BOJ 고스택(3425) - Java  (0) 2021.09.13
BOJ 사다리 조작(15684) - Java  (0) 2021.09.07
BOJ 인구 이동(16234) - Java  (0) 2021.09.04

문제 - https://www.acmicpc.net/problem/3425

 

3425번: 고스택

각각의 입력값에 대해서, 해당하는 프로그램을 수행한 뒤, 출력값을 출력하면 된다. 출력값이란 스택에 저장되어 있는 숫자이다. 만약, 프로그램 에러가 발생하거나, 모든 수행이 종료됐을 때

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {

    static BufferedReader br;
    static BufferedWriter bw;
    static StringTokenizer st;

    static Stack<Integer> stack;
    static ArrayList<String> Task;

    public static void main(String[] args) throws Exception {
        br = new BufferedReader(new InputStreamReader(System.in));
        bw = new BufferedWriter(new OutputStreamWriter(System.out));

        while (true){
            String input = br.readLine();
            if (input.equals("QUIT"))
                break;

            Task = new ArrayList<>();
            while (!input.equals("END")){
                Task.add(input);
                input = br.readLine();
            }

            int N = Integer.parseInt(br.readLine());
            for (int i = 0; i < N; i++) {
                stack = new Stack<>();
                stack.push(Integer.parseInt(br.readLine()));
                if (run())
                    bw.write(stack.pop()+"\n");
                else
                    bw.write("ERROR\n");
            }
            bw.write("\n");
            br.readLine();
        }

        bw.flush();
        bw.close();
        br.close();
    }
    static boolean run(){
        for (String line : Task) {
            st = new StringTokenizer(line);
            String cmd = st.nextToken();

            if (cmd.equals("NUM")){
                stack.push(Integer.parseInt(st.nextToken()));
            }
            else if (cmd.equals("POP")){
                if (stack.empty())
                    return false;
                stack.pop();
            }
            else if (cmd.equals("INV")){
                if (stack.empty())
                    return false;
                stack.push(-stack.pop());
            }
            else if (cmd.equals("DUP")){
                if (stack.empty())
                    return false;
                stack.push(stack.peek());
            }
            else if (cmd.equals("SWP")){
                if (stack.empty())
                    return false;
                int A = stack.pop();
                if (stack.empty())
                    return false;
                int B = stack.pop();
                stack.push(A);
                stack.push(B);
            }
            else if (cmd.equals("ADD")){
                if (stack.empty())
                    return false;
                int A = stack.pop();
                if (stack.empty())
                    return false;
                int B = stack.pop();
                if (Math.abs(A+B)>1000000000)
                    return false;
                stack.push(A+B);
            }
            else if (cmd.equals("SUB")){
                if (stack.empty())
                    return false;
                int A = stack.pop();
                if (stack.empty())
                    return false;
                int B = stack.pop();
                if (Math.abs(B-A)>1000000000)
                    return false;
                stack.push(B-A);
            }
            else if (cmd.equals("MUL")){
                if (stack.empty())
                    return false;
                long A = stack.pop();
                if (stack.empty())
                    return false;
                long B = stack.pop();
                if (Math.abs(A*B)>1000000000)
                    return false;
                stack.push((int) (A*B));
            }
            else if (cmd.equals("DIV")){
                if (stack.empty())
                    return false;
                int A = stack.pop();
                if (stack.empty() || A==0)
                    return false;
                int B = stack.pop();
                if (((A>0 && B<0) || (A<0 && B>0)))
                    stack.push(-(Math.abs(B)/Math.abs(A)));
                else
                    stack.push(Math.abs(B)/Math.abs(A));
            }
            else if (cmd.equals("MOD")){
                if (stack.empty())
                    return false;
                int A = stack.pop();
                if (stack.empty() || A==0)
                    return false;
                int B = stack.pop();
                if (B<0)
                    stack.push(-(Math.abs(B)%Math.abs(A)));
                else
                    stack.push(Math.abs(B)%Math.abs(A));
            }
        }
        if (stack.size()!=1)
            return false;
        return true;
    }
}

크게 어려움은 없었지만, 자료형 변환을 미처 신경쓰지못해 몇차례 틀렸다.

Integer는 약 20억까지 표현 가능하다는걸 명심하자.

'공부 > algorithm' 카테고리의 다른 글

BOJ LCA 2(11438) - Java  (0) 2021.09.13
BOJ AC(5430) - Java  (0) 2021.09.13
BOJ 사다리 조작(15684) - Java  (0) 2021.09.07
BOJ 인구 이동(16234) - Java  (0) 2021.09.04
BOJ 상어 중학교(21609) - Java  (0) 2021.09.02

문제 - https://www.acmicpc.net/problem/15684

 

15684번: 사다리 조작

사다리 게임은 N개의 세로선과 M개의 가로선으로 이루어져 있다. 인접한 세로선 사이에는 가로선을 놓을 수 있는데, 각각의 세로선마다 가로선을 놓을 수 있는 위치의 개수는 H이고, 모든 세로선

www.acmicpc.net

import java.awt.image.AreaAveragingScaleFilter;
import java.io.*;
import java.util.*;

public class Main {

    static int N, M, H, cnt=0;
    static int[][] ladder;

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        H = Integer.parseInt(st.nextToken());
        ladder = new int[N][H]; // ladder[i][j] : i번째 세로선의 j번째 가로선을 지나면 위치하게되는 세로선의 번호

        for (int i = 1; i < N; i++) {
            Arrays.fill(ladder[i], i); // i번째 세로선에서 갈 수 있는 모든 세로선 번호는 모두 i
        }

        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken())-1;
            int b = Integer.parseInt(st.nextToken())-1;
            ladder[b][a] = b+1; // b번째 세로선의 a번째 가로선 위치를 지나면 b+1번째 세로선으로 이동
            if (b<N-1)
                ladder[b+1][a] = b; // 양방향
        }

        while(cnt<4){ // 4개를 고르기 전까지
            if (pick(0, 0, cnt)) // 골라서 만족하면
                break; // 멈추고
            cnt++; // 아니면 고르는 갯수 증가
        }
        bw.write(cnt<4 ? cnt+"\n" : "-1\n");

        bw.flush();
        bw.close();
        br.close();
    }
    static boolean pick(int line, int level, int remain){
        if (remain==0)
            return chk();

        for (int i = line; i < N-1; i++) {
            for (int j = line==i ? level : 0; j < H; j++) {
                if (ladder[i][j] != i || (i<N-1 && ladder[i+1][j]!=i+1)) // 이미 가로선이 놓여져있거나, 옆세로선에 가로선이 놓여져있으면
                    continue; // 패스
                ladder[i][j] = i+1; // 옆으로 가는 가로선 표시하고
                if (i<N-1)
                    ladder[i+1][j] = i; // 옆선도 표시
                if (pick(i, j, remain-1)) // 조건 만족하면
                    return true; // 바로 종료
                ladder[i][j] = i;
                if (i<N-1)
                    ladder[i+1][j] = i+1;
            }
        }
        return false;
    }
    static boolean chk(){
        for (int start = 0; start < N; start++) {
            int nextline = start;
            for (int step = 0; step < H; step++) {
                nextline = ladder[nextline][step];
            }
            if (nextline!=start)
                return false;
        }
        return true;
    }
}

 

 

나름대로 깔끔하게 풀었다고 생각해서 런타임 상위권을 예상했지만, 정말 빠른 사람들과는 말도 안되게 많이 차이났다..

개선할 필요가 있는거같은데, 어느부분을 개선시켜야할지 모르겠다..

'공부 > algorithm' 카테고리의 다른 글

BOJ AC(5430) - Java  (0) 2021.09.13
BOJ 고스택(3425) - Java  (0) 2021.09.13
BOJ 인구 이동(16234) - Java  (0) 2021.09.04
BOJ 상어 중학교(21609) - Java  (0) 2021.09.02
BOJ 경사로(14890) - Java  (0) 2021.09.02

문제 - https://www.acmicpc.net/problem/16234

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {

    static int N, L, R, Day = 0;
    static int[] dr = {-1, 0, 1, 0};
    static int[] dc = {0, 1, 0, -1};
    static int[][] A;
    static class Nation{
        int r, c;
        public Nation(int r, int c){
            this.r = r;
            this.c = c;
        }
    }
    static class United{
        int all;
        ArrayList<Nation> nations;
        public United(){
            this.all = 0;
            this.nations = new ArrayList<>();
        }
    }static ArrayList<United> unites;

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        L = Integer.parseInt(st.nextToken());
        R = Integer.parseInt(st.nextToken());

        A = new int[N][N];
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < N; j++) {
                A[i][j] = Integer.parseInt(st.nextToken());
            }
        }
    
        while(true){
            lookup();
            if (unites.size()==0)
                break;
            move();
            Day++;
        }
        bw.write(Day+"\n");
    
        bw.flush();
        bw.close();
        br.close();
    }
    static void lookup(){
        boolean[][] visit = new boolean[N][N];
        unites = new ArrayList<>();

        for (int i = 0; i < N; i++) { // 0행 부터 N-1행까지
            for (int j = 0; j < N; j++) {
                Nation from = new Nation(i, j);
                for (int w = 1; w < 3; w++) { // 오른쪽하고 아랫쪽만 확인
                    Nation to = new Nation(i + dr[w], j + dc[w]);

                    if(can_move(from, to) && !visit[to.r][to.c]){ // 갈 수 있고, 간적없으면,
                        United tmp = new United(); // 새로운 연합 만들고,
                        Queue<Nation> Q = new LinkedList();
                        Q.add(from);
                        visit[from.r][from.c] = true;
                        while (!Q.isEmpty()){ // BFS
                            Nation cur = Q.poll();
                            tmp.nations.add(cur); // 연합에 추가
                            tmp.all += A[cur.r][cur.c]; // 연합인구 추가
                            for (int k = 0; k < 4; k++) {
                                Nation next = new Nation(cur.r + dr[k], cur.c + dc[k]);
                                if(can_move(cur, next) && !visit[next.r][next.c]) {// 갈 수 있고, 간적없으면,
                                    Q.add(next);
                                    visit[next.r][next.c] = true; // 확인
                                }
                            }
                        }
                        unites.add(tmp);
                    }

                }
            }
        }
    }
    static boolean can_move(Nation from, Nation to){
        if (0<=to.r && to.r<N && 0<= to.c && to.c<N // 범위안에 있고
                && L <= Math.abs(A[to.r][to.c] - A[from.r][from.c]) // 최솟값 만족하고
                && Math.abs(A[to.r][to.c] - A[from.r][from.c]) <= R) // 최댓값 만족하면
            return true; // 이동가능
        return false; // 이동못함
    }
    static void move(){
        for (United united : unites){
            int population = united.all / united.nations.size();
            for (Nation nation : united.nations){
                A[nation.r][nation.c] = population;
            }
        }
    }
}

상어중학교 문제와 굉장히 비슷한 문제다.

BFS만 논리적으로 문제없이 구현한다면, 크게 무리없이 해결할 수 있는 문제로 보인다.

'공부 > algorithm' 카테고리의 다른 글

BOJ 고스택(3425) - Java  (0) 2021.09.13
BOJ 사다리 조작(15684) - Java  (0) 2021.09.07
BOJ 상어 중학교(21609) - Java  (0) 2021.09.02
BOJ 경사로(14890) - Java  (0) 2021.09.02
BOJ 상어 초등학교(21608) - Java  (0) 2021.08.31

문제 - https://www.acmicpc.net/problem/21609

 

21609번: 상어 중학교

상어 중학교의 코딩 동아리에서 게임을 만들었다. 이 게임은 크기가 N×N인 격자에서 진행되고, 초기에 격자의 모든 칸에는 블록이 하나씩 들어있고, 블록은 검은색 블록, 무지개 블록, 일반 블록

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {

    static int N, M, score = 0;
    static int[] dr = {-1, 0, 1, 0};
    static int[] dc = {0, 1, 0, -1};
    static int[][] map;
    static Queue<Point> Q;
    static class Block{
        int main;
        ArrayList<Point> nonrain, rain;
        public Block(Point p, int color){
            this.main = color;
            this.nonrain = new ArrayList<>();
            this.rain = new ArrayList<>();
            this.nonrain.add(p);
        }
        public int size(){
            return this.nonrain.size() + this.rain.size();
        }
    }
    static class Point{
        int r, c;
        public Point(int r, int c){
            this.r = r;
            this.c = c;
        }
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        map = new int[N][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());
            }
        }

        while(true){
            Block best = find(); // 가장 큰 블록 찾고
            if (best==null) // 없으면
                break; // 종료
            remove(best); // 찾은 블록 없애고, 점수추가
            drop(); // 중력적용
            rotate(); // 회전
            drop(); // 중력적용
        }
        bw.write(score+"\n");

        bw.flush();
        bw.close();
        br.close();
    }
    static Block find(){
        Block best = new Block(new Point(0, 0), 0);
        boolean[][] visit = new boolean[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (map[i][j]>0 && !visit[i][j]) { // 색이 존재하고, 확인한적 없으면
                    visit[i][j] = true;
                    Block tmp = new Block(new Point(i, j), map[i][j]); // 새 블록만들고
                    Q = new LinkedList();
                    Q.add(new Point(i, j));
                    while (!Q.isEmpty()){
                        Point now = Q.poll();
                        for (int w = 0; w < 4; w++) { // 4방향 돌면서
                            Point nxt = new Point(now.r+dr[w], now.c+dc[w]);
                            if (0<=nxt.r && nxt.r<N && 0<=nxt.c && nxt.c<N && !visit[nxt.r][nxt.c] && (map[nxt.r][nxt.c]==0 || map[nxt.r][nxt.c]==tmp.main)){ // 확인한적없고, 조건 만족하면
                                Q.add(nxt);
                                if (map[nxt.r][nxt.c]==0) // 무지개 블록 추가
                                    tmp.rain.add(nxt);
                                else
                                    tmp.nonrain.add(nxt);
                                visit[nxt.r][nxt.c] = true; // 표시.
                            }
                        }
                    }
                    for (Point p : tmp.rain){ // 블록 원소들 중 무지개 색은
                        visit[p.r][p.c] = false; // 다시 확인 안하걸로 표시
                    }
                    if((tmp.size()>=2 && tmp.size()>best.size()) || (tmp.size()>=2 && tmp.size()==best.size() && tmp.rain.size() >= best.rain.size())) // 최선책 갱신
                        best = tmp;
                }
            }
        }
        return best.main!=0 ? best : null;
    }
    static void remove(Block block){
        score += block.size()*block.size(); // score 추가
        for (Point p : block.nonrain){ // 블록에 있는 모든 무지개 아닌 원소들
            map[p.r][p.c] = -2; // 전부 빈값으로.
        }
        for (Point p : block.rain){ // 블록에 있는 모든 무지개 원소들
            map[p.r][p.c] = -2; // 전부 빈값으로.
        }
    }
    static void drop(){
        for (int j = 0; j < N; j++) {
            for (int i = N-2; i >= 0; i--) { // 왼쪽 아랫 행부터 위로 살펴보며
                if(map[i][j] > -1 && map[i+1][j] == -2) { // 지금은 있는데, 아랫쪽 색이 비어있으면,
                    int k=i;
                    while (k < N-1 && map[k+1][j] == -2) { // 다음칸이 비어있을때까지 밑으로 내리기
                        map[k + 1][j] = map[k][j];
                        map[k][j] = -2;
                        k++;
                    }
                }
            }
        }
    }
    static void rotate(){
        int[][] tmp = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                tmp[N-1-j][i] = map[i][j]; // 왼쪽으로 90도 회전
            }
        }
        map = tmp;
    }
}

빡구현 문제다.

그러나 문제자체가 그렇게 어렵진 않았다.

다만, 문제 조건을 꼼꼼하게 확인안해서 정말 디버깅하는데 한참이 걸렸다...

 

'공부 > algorithm' 카테고리의 다른 글

BOJ 사다리 조작(15684) - Java  (0) 2021.09.07
BOJ 인구 이동(16234) - Java  (0) 2021.09.04
BOJ 경사로(14890) - Java  (0) 2021.09.02
BOJ 상어 초등학교(21608) - Java  (0) 2021.08.31
BOJ 전구(2449) - Java  (0) 2021.08.25

문제 - https://www.acmicpc.net/problem/14890

 

14890번: 경사로

첫째 줄에 N (2 ≤ N ≤ 100)과 L (1 ≤ L ≤ N)이 주어진다. 둘째 줄부터 N개의 줄에 지도가 주어진다. 각 칸의 높이는 10보다 작거나 같은 자연수이다.

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {

    static int N, L, cnt = 0;
    static int[][] map;

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        L = Integer.parseInt(st.nextToken());
        map = new int[N][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++) {
            if (chk(map[i])) // 행 체크
                cnt++;

            int[] vertical = new int[N];
            for (int j = 0; j < N; j++) {
                vertical[j] = map[j][i];
            }
            if (chk(vertical)) // 열 체크
                cnt++;
        }
        bw.write(cnt+"\n");

        bw.flush();
        bw.close();
        br.close();
    }
    static boolean chk(int[] road){
        boolean[] visit = new boolean[N];
        for (int i = 0; i < N-1; i++) {
            if(Math.abs(road[i] - road[i+1]) > 1) // 높이 차이 많이나면 못지나감
                return false;

            if(road[i] > road[i+1]) // 하강
                for (int j = i+1; j <= i+L; j++) { // 현재위치 다음부터, L만큼 순회하면서
                    if(j==N || visit[j] || road[j]!=road[i+1]) // 순회도중 범위를 벗어나거나, 이미 발판이 놓였거나, 높이가 일정하지 않으면,
                        return false; // 못지나감
                    visit[j] = true; // 발판놓기
                }

            if(road[i] < road[i+1]) // 상승
                for (int j = i; j > i-L; j--) { // 현재위치부터, L만큼 전으로 돌아가며
                    if(j<0 || visit[j] || road[j]!=road[i]) // 범위를 벗어나거나, 이미 발판이 놓였거나, 높이가 일정하지 않으면,
                        return false; // 못지나감
                    visit[j] = true; // 발판놓기
                }
        }
        return true; // 통과
    }
}

간단한 문제처럼 보였는데

상승, 하강 두가지를 신경쓰다보니 생각보다 구현에 애를 많이 먹었던것같다..

'공부 > algorithm' 카테고리의 다른 글

BOJ 인구 이동(16234) - Java  (0) 2021.09.04
BOJ 상어 중학교(21609) - Java  (0) 2021.09.02
BOJ 상어 초등학교(21608) - Java  (0) 2021.08.31
BOJ 전구(2449) - Java  (0) 2021.08.25
BOJ 제단(5626) - Java  (0) 2021.08.25

문제 - https://www.acmicpc.net/problem/21608

 

21608번: 상어 초등학교

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호

www.acmicpc.net

import java.io.*;
import java.util.*;

public class Main {

    static int N;
    static int[] dr = {-1, 0, 1, 0};
    static int[] dc = {0, 1, 0, -1};
    static int[][] map;
    static Set[] friend;

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st;

        N = Integer.parseInt(br.readLine());
        map = new int[N][N];
        friend = new Set[N*N+1];
        for (int i = 0; i < N*N; i++) {
            st = new StringTokenizer(br.readLine());
            int id = Integer.parseInt(st.nextToken());
            friend[id] = new HashSet();
            for (int j = 0; j < 4; j++) {
                friend[id].add(Integer.parseInt(st.nextToken()));
            }
            fill(id);
        }
        bw.write(calc()+"\n");

        bw.flush();
        bw.close();
        br.close();
    }
    static void fill(int id){
        int empty = 0;
        int like = 0;
        int row = 0;
        int col = 0;
        for (int i = N-1; i >= 0; i--) {
            for (int j = N-1; j >= 0; j--) {
                if (map[i][j]==0){ // 빈자리면
                    int tmp_empty = 0;
                    int tmp_like = 0;
                    for (int w = 0; w < 4; w++) { // 4방향 돌면서
                        int nr = i + dr[w];
                        int nc = j + dc[w];
                        if(0<=nr && nr<N && 0<=nc && nc<N){ // 교실안에있으면
                            if (map[nr][nc]==0) // 빈자리 수 세고
                                tmp_empty++;
                            else if (friend[id].contains(map[nr][nc])) // 좋아하는 학생 수 세고
                                tmp_like++;
                        }
                    }
                    if ((tmp_like > like) || (tmp_like == like && tmp_empty >= empty)){ // 좋아하는 학생 수가 더 많거나, 같은데 빈자리수가 같거나 더 많으면 위치 갱신 위치 새로 갱신
                        like = tmp_like;
                        empty = tmp_empty;
                        row = i;
                        col = j;
                    }
                }
            }
        }
        map[row][col] = id;
    }

    static int calc(){
        int score = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                int cnt = 0;
                int id = map[i][j];
                for (int k = 0; k < 4; k++) {
                    int nr = i+dr[k];
                    int nc = j+dc[k];
                    if (0<=nr && nr<N && 0<=nc && nc<N && friend[id].contains(map[nr][nc]))
                        cnt++;
                }
                score += cnt > 0 ? Math.pow(10, cnt-1) : 0;
            }
        }
        return score;
    }
}

특별할 것 없는 단순 구현문제였다.

다만, Python이 Java보다 더 퍼포먼스가 좋은 것 같은데.. 이유는 잘 모르겠다!

'공부 > algorithm' 카테고리의 다른 글

BOJ 상어 중학교(21609) - Java  (0) 2021.09.02
BOJ 경사로(14890) - Java  (0) 2021.09.02
BOJ 전구(2449) - Java  (0) 2021.08.25
BOJ 제단(5626) - Java  (0) 2021.08.25
BOJ 연구소(14502) - Java  (0) 2021.08.24

+ Recent posts