λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ”Ž Algorithm/πŸ’» 문제 풀이

[λ°±μ€€] 1799. λΉ„μˆ

by Seongpyo Hong 2021. 3. 7.

문제


풀이

μ²˜μŒμ— μƒκ°ν–ˆλ˜ 방법은 μ™„μ „ 탐색을 톡해 μ΅œλŒ€ 수λ₯Ό μ°ΎλŠ” λ°©λ²•μ΄μ—ˆλ‹€. 쀑간에 κ°€μ§€μΉ˜κΈ°λ₯Ό 톡해 μ‹œκ°„μ„ 쀄일 수 μžˆκ² μ§€λ§Œ n의 μ΅œλŒ€κ°’μ΄ 100이고 (λͺ¨λ“  점에 λŒ€ν•΄ λ†“λŠ” 경우/ 놓지 μ•ŠλŠ” 경우) * (놓을 수 μžˆλŠ”μ§€ νŒλ‹¨ν•˜κΈ° μœ„ν•΄ μ–‘ λŒ€κ°μ„ μ„ νƒμƒ‰ν•˜λŠ” 경우)λ₯Ό ν•˜κ²Œ 되면 O(2^n * n)이기 λ•Œλ¬Έμ— μ‹œκ°„μ΄ˆκ³Όκ°€ λ°œμƒν•  것 κ°™μ•„μ„œ λ‹€λ₯Έ 방법을 생각해봀닀.

μƒκ°ν•œ 방법은 N-Queensμ—μ„œ λͺ¨λ“  행렬을 μ €μž₯ν•˜μ§€ μ•Šκ³  ν•΄λ‹Ή idxμ—λŠ” ν•˜λ‚˜μ˜ κ°’λ§Œ 올 수 μžˆλ„λ‘ ν•œλ‹€λ©΄ μ‹œκ°„μ„ 쀄일 수 μžˆλ‹€λŠ” 생각을 ν–ˆκ³  데이터λ₯Ό μ–΄λ–»κ²Œ λ¬Άμ–΄μ•Ό 할지 고민을 ν•΄λ΄€λ‹€. N-Queensμ—μ„œ queen은 κ°€λ‘œ,μ„Έλ‘œλ₯Ό 갈 수 μžˆμ—ˆκ³  이둜 인해 ν•˜λ‚˜μ˜ 행에 퀸을 놓을 κ²½μš°μ—λŠ” 같은 ν–‰μ—λŠ” 퀀이 μ‘΄μž¬ν•˜μ§€ λͺ»ν•˜λŠ” μ„±μ§ˆμ„ μ΄μš©ν–ˆμ—ˆλ‹€. 이와 μœ μ‚¬ν•˜κ²Œ λŒ€κ°μ„ μ„ ν•˜λ‚˜μ˜ μ§‘ν•©μœΌλ‘œ λ¬Άμ–΄μ„œ μ²˜λ¦¬ν–ˆλ‹€. 이 집합은 cacheλΌλŠ” λ°°μ—΄λ‘œ 2N - 1개의 λŒ€κ°μ„ μ΄ μ‘΄μž¬ν•˜λ―€λ‘œ ν¬κΈ°λŠ” 2N - 1으둜 μ„€μ •, μ €μž₯ν•˜λŠ” 값은 ν•΄λ‹Ή λŒ€κ°μ„ μ— λ†“λŠ” 점의 Xμ’Œν‘œλ₯Ό μ €μž₯ν•˜μ˜€λ‹€. ν•΄λ‹Ή 방법을 μ΄μš©ν•˜κ²Œ 되면 각 λŒ€κ°μ„ μ— 어디에 놓을지 κ²°μ •ν•˜λŠ” 것과 κ°™κΈ° 떄문에 O(n * (n-1)!)의 μ‹œκ°„ λ³΅μž‘λ„λ₯Ό 가지고 μ‹€μ œλ‘œλŠ” κ°€μ§€μΉ˜κΈ°λ₯Ό 톡해 더 적은 경우의 수λ₯Ό 탐색할 수 μžˆλ‹€.

λŒ€κ°μ„  집합

이 λ•Œ, ν•˜λ‚˜μ˜ μ§‘ν•©μ—μ„œ 점을 μˆœμ„œλŒ€λ‘œ μ„ νƒν•˜κΈ° μœ„ν•œ κ·œμΉ™μ„ λ‹€μŒκ³Ό κ°™λ‹€. μ™Όμͺ½ 상단뢀터 idx = 0이라고 ν•˜λ©΄,

  • idx = 0 : (0,0)
  • idx = 1 : (0,1), (1,0)
  • idx = 2 : (0,2), (1,1), (2.0) 

즉 xμ’Œν‘œλŠ” 0~idxκΉŒμ§€μ˜ λ²”μœ„μ—μ„œ 순차적으둜 μ¦κ°€ν•˜κ³  이 λ•Œ yμ’Œν‘œλŠ” idx - xκ°€ λœλ‹€. 즉, (x,idx - x)의 μ’Œν‘œκ°€ ν•΄λ‹Ή λŒ€κ°μ„ μ— μ†ν•˜λŠ” 점이닀.

μ—¬κΈ°μ„œ κ³ λ €ν•΄μ•Ό ν•  점이  idxκ°€ N을 λ„˜μ–΄κ°”μ„ κ²½μš°μ—λŠ” λͺ¨λ“  점이 λ‹€ μ†ν•˜λŠ”κ²Œ μ•„λ‹ˆκ²Œ λœλ‹€. μœ„μ˜ κ·Έλ¦Όμ—μ„œ λ‹€μŒ λŒ€κ°μ„ μ— μ†ν•˜λŠ” 점을 μœ„μ˜ κ³΅μ‹μœΌλ‘œ ꡬ해보면 (0,5), (1,4), (2,3), (3,2), (4,1), (5,0)μ΄μ§€λ§Œ ν•΄λ‹Ή λ°°μ—΄ λ²”μœ„μ— ν¬ν•¨λ˜μ§€ μ•ŠλŠ” 점도 μ‘΄μž¬ν•œλ‹€. λ”°λΌμ„œ 이에 λŒ€ν•œ μ˜ˆμ™Έμ²˜λ¦¬κ°€ ν•„μš”ν•˜λ‹€. 

λ²”μœ„μ— λ§Œμ‘±ν•˜κ³ , 놓을 수 μžˆλŠ” 경우(ν˜„μž¬ 칸에 λΉ„μˆμ„ 놓을 수 있고 λ°˜λŒ€ λ°©ν–₯ λŒ€κ°μ„ μ— λΉ„μˆμ΄ μ—†λŠ” 경우)μ—λŠ” cache[idx]λ₯Ό xμ’Œν‘œλ‘œ κ°±μ‹ ν•˜κ³  λΉ„μˆ cntλ₯Ό ν•˜λ‚˜μ”© μ¦κ°€μ‹œμΌœ λ‹€μŒ idx에 λŒ€ν•œ 검사λ₯Ό μˆ˜ν–‰ν•œλ‹€. μ΅œμ’…μ μœΌλ‘œ idxκ°€ λŒ€κ°μ„  κ°œμˆ˜μ™€ κ°™μ•„μ§€λŠ” 경우 maxCntλ₯Ό κ°±μ‹ ν•˜κ³  λ¦¬ν„΄ν•˜κ²Œ λœλ‹€.

private static void putBishop(int idx, int cnt) {
        if (idx == (2 * N) - 1) {
            if (macCnt < cnt) macCnt = cnt;
            return;
        }

        boolean isExist = false;
        for (int i = 0; i <= idx; i++) {
            if (i >= N || idx - i >= N || map[i][idx - i] == 0 || !isAvailable(i, idx - i, idx)) continue;
            cache[idx] = i;
            putBishop(idx + 1, cnt + 1);
            isExist = true;
        }
        if (!isExist) {
            cache[idx] = -1;
            putBishop(idx + 1, cnt);
        }
    }

μœ„μ˜ μ½”λ“œμ—μ„œ isExistλŠ” ν•΄λ‹Ή λŒ€κ°μ„ μ— 놓을 수 μžˆλŠ” 점이 μ‘΄μž¬ν•˜λŠ”μ§€ νŒλ‹¨ν•˜λŠ” ν”Œλž˜κ·Έμ΄λ‹€. ν•΄λ‹Ή λŒ€κ°μ„ μ— 놓을 수 μ—†λŠ” κ²½μš°μ—λŠ” cntλŠ” κ·ΈλŒ€λ‘œ, cache[idx] = -1을 μ €μž₯ν•œλ‹€.


λ‹€μŒμœΌλ‘œ ν•΄μ•Όν•  μž‘μ—…μ€ λ°˜λŒ€ λ°©ν–₯ λŒ€κ°μ„ μ— λΉ„μˆμ΄ μ‘΄μž¬ν•˜λŠ”μ§€ ν™•μΈν•˜λŠ” μž‘μ—…μ΄λ‹€. 이에 λŒ€ν•œ κ·œμΉ™μ€ λ‹€μŒκ³Ό 같이 μ •μ˜ν–ˆλ‹€. 

ν˜„μž¬ λŒ€κ°μ„ μ΄ idx번이고 μ’Œν‘œκ°€ (x,y)인 경우, κ²€μ‚¬λŠ” idx - 2인 λŒ€κ°μ„ λΆ€ν„°  (x-1, y-1)을 κ²€μ‚¬ν•˜λ©΄ λœλ‹€. μ—¬κΈ°μ„œ cache에 xμ’Œν‘œλ₯Ό μ €μž₯ν–ˆκΈ° λ•Œλ¬Έμ— cache[idx - 2] = x -1인지λ₯Ό idxκ°€ 0보닀 클 λ•ŒκΉŒμ§€ λ°˜λ³΅ν•΄μ„œ κ²€μ‚¬ν•˜λ©΄ λœλ‹€.

    private static boolean isAvailable(int x, int y, int idx) {
        while(idx >= 2 && x >= 1 && y >= 1) {
            idx -= 2;
            x -= 1;
            y -= 1;
            if (cache[idx] == x) return false;
        }

        return true;
    }

μ΅œμ’… μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

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

public class Solution1799 {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static int N, macCnt;
    static int[] cache;
    static int[][] map;
    public static void main(String[] args) throws IOException {
        N = Integer.parseInt(br.readLine());
        cache = new int[2 * N - 1];
        map = new int[N][N];
        for (int i = 0; i < N; i++) {
            String[] line = br.readLine().split(" ");
            for (int j = 0; j < N; j++) {
                map[i][j] = Integer.parseInt(line[j]);
            }
        }

        putBishop(0, 0);
        System.out.println(macCnt);
    }

    private static void putBishop(int idx, int cnt) {
        if (idx == (2 * N) - 1) {
            if (macCnt < cnt) macCnt = cnt;
            return;
        }

        boolean isExist = false;
        for (int i = 0; i <= idx; i++) {
            if (i >= N || idx - i >= N || map[i][idx - i] == 0 || !isAvailable(i, idx - i, idx)) continue;
            cache[idx] = i;
            putBishop(idx + 1, cnt + 1);
            isExist = true;
        }
        if (!isExist) {
            cache[idx] = -1;
            putBishop(idx + 1, cnt);
        }
    }

    private static boolean isAvailable(int x, int y, int idx) {
        while(idx >= 2 && x >= 1 && y >= 1) {
            idx -= 2;
            x -= 1;
            y -= 1;
            if (cache[idx] == x) return false;
        }

        return true;
    }
}

 

 

λŒ“κΈ€