[BOJ] 14891. 톱니바퀴 - Simulation

제출일 : 2019-10-14

문제 풀이 시간 : 1H

난이도 : ★★★

Problem

link : https://www.acmicpc.net/problem/14891

Input

첫째 줄에 1번 톱니바퀴의 상태, 둘째 줄에 2번 톱니바퀴의 상태, 셋째 줄에 3번 톱니바퀴의 상태, 넷째 줄에 4번 톱니바퀴의 상태가 주어진다. 상태는 8개의 정수로 이루어져 있고, 12시방향부터 시계방향 순서대로 주어진다. N극은 0, S극은 1로 나타나있다.

다섯째 줄에는 회전 횟수 K(1 ≤ K ≤ 100)가 주어진다. 다음 K개 줄에는 회전시킨 방법이 순서대로 주어진다. 각 방법은 두 개의 정수로 이루어져 있고, 첫 번째 정수는 회전시킨 톱니바퀴의 번호, 두 번째 정수는 방향이다. 방향이 1인 경우는 시계 방향이고, -1인 경우는 반시계 방향이다.

Output

총 K번 회전시킨 이후에 네 톱니바퀴의 점수의 합을 출력한다. 점수란 다음과 같이 계산한다.

  • 1번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 1점
  • 2번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 2점
  • 3번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 4점
  • 4번 톱니바퀴의 12시방향이 N극이면 0점, S극이면 8점

Example

input

10101111
01111101
11001110
00000010
2
3 -1
1 1

output

7

Solution & Inpression

Code

언어 : JAVA

메모리 : 14,536 kb

실행시간 : 124 ms

import java.util.*;

public class Main {
    static int[][] wheels;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        wheels = new int[5][8];
        for (int i = 1; i <= 4; i++) {
            String str = sc.next();
            for (int j = 0; j < 8; j++) {
                if (str.charAt(j) == '1')
                    wheels[i][j] = 1; // S극
                else
                    wheels[i][j] = 0; // N극
            }
        }

        int K = sc.nextInt(); // 회전 횟수 K;
        for (int i = 0; i < K; i++) {
            // 톱니바퀴 번호, 방향(1:시계 -1:반시계)
            isspin(sc.nextInt(), sc.nextInt());
        }

        System.out.println(1 * wheels[1][0] 
                         + 2 * wheels[2][0] 
                         + 4 * wheels[3][0] 
                         + 8 * wheels[4][0]);

        sc.close();
    }

    //좌우에 톱니를 회전할 수 있는지 확인.
    private static void isspin(int num, int dir) { 
        //회전이 가능한 톱니번호와 뱡향을 저장
        ArrayList<int[]> list = new ArrayList<>(); 

        list.add(new int[] { num, dir });

        int flag = dir;
        int temp = num;
        int right = wheels[num][2]; //현재 바퀴의 오른쪽값.
        while (temp + 1 <=4) { // 오른쪽에 바퀴가 존재한다면
            if (right != wheels[temp + 1][6]) {//회전이 가능한지 
                temp++;
                flag *= -1;
                right = wheels[temp][2]; 
                list.add(new int[] { temp, flag });
            }
            else
                break;
        }

        flag = dir;
        temp = num;
        int left = wheels[num][6]; //현재 바퀴의 왼쪽값.
        while (temp - 1 >=1) { // 왼쪽에 바퀴가 존재한다면
            if (left != wheels[temp - 1][2]) { //회전이 가능한지
                temp--;
                flag *= -1; //반대방향
                left = wheels[temp][6]; 
                list.add(new int[] { temp, flag });
            }
            else
                break;
        }
        for (int i = 0; i < list.size(); i++) {
            spin(list.get(i)[0], list.get(i)[1]);
        }
    }

    private static void spin(int num, int dir) {
        int[] temp = wheels[num].clone(); // 복사

        if (dir == 1) {// 시계방향이면 >> 오른쪽으로 한칸씩
            for (int i = 1; i < 8; i++) {
                wheels[num][i] = temp[i - 1];
            }
            wheels[num][0] = temp[7];
        } else {// 반시계방향이면 >> 왼쪽으로 한칸씩
            for (int i = 1; i < 8; i++) {
                wheels[num][i - 1] = temp[i];
            }
            wheels[num][7] = temp[0];
        }
    }
}

[BOJ] 14890. 경사로 - Simulation

제출일 : 2019-10-14

문제 풀이 시간 : 2H

난이도 : ★★★★☆

Problem

link : https://www.acmicpc.net/problem/14890

Input

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

Output

첫째 줄에 지나갈 수 있는 길의 개수를 출력한다.

Example

input

6 2
3 3 3 3 3 3
2 3 3 3 3 3
2 2 2 3 2 3
1 1 1 2 2 2
1 1 1 3 3 1
1 1 2 3 3 2

output

3

Solution & Inpression

해결하지 못한 문제.

Code

언어 : JAVA

메모리 : 25,868 kb

실행시간 : 240 ms

import java.util.*;

public class Main {
    static int[][] wheels;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        wheels = new int[5][8];
        for (int import java.util.ArrayList;
import java.util.Scanner;

public class Main {

    static int N, L;
    static int[][] map;
    static boolean[][] visitRow, visitCol;

    static ArrayList<int[]> v;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        N = sc.nextInt();
        L = sc.nextInt();

        map = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                map[i][j] = sc.nextInt();
            }
        }    
        int ans = 0;
        int j = 0;// 끝에 도착시 j로 체크
        for (int i = 0; i < N; i++) {
            int cnt = 1;
            for (j = 0; j < N-1; j++) { //가로: 좌->우
                     if(map[i][j]  ==map[i][j+1])            cnt++; //평지
                else if(map[i][j]+1==map[i][j+1] && cnt>= L) cnt=1; //오르막
                else if(map[i][j]-1==map[i][j+1] && cnt>= 0) cnt=-L+1; //내리막
                else break;
            }
            if(j==N-1 && cnt>= 0) ans++; //끝에 도착

            cnt=1;
            for (j = 0; j < N-1; j++) { //세로: 상->하
                     if(map[j][i]  ==map[j+1][i])            cnt++; //평지
                else if(map[j][i]+1==map[j+1][i] && cnt>= L) cnt=1; //오르막
                else if(map[j][i]-1==map[j+1][i] && cnt>= 0) cnt=-L+1; //내리막
                else break;
            }
            if(j==N-1 && cnt>= 0) ans++; //끝에 도착

        }

        System.out.println(ans);
    }
}

[BOJ] 14889. 스타트와 링크- Permutation

제출일 : 2019-10-14

문제 풀이 시간 : 40M

난이도 : ★★

Problem

link : https://www.acmicpc.net/problem/148989

Input

첫째 줄에 N(4 ≤ N ≤ 20, N은 짝수)이 주어진다. 둘째 줄부터 N개의 줄에 S가 주어진다. 각 줄은 N개의 수로 이루어져 있고, i번 줄의 j번째 수는 Sij 이다. Sii는 항상 0이고, 나머지 Sij는 1보다 크거나 같고, 100보다 작거나 같은 정수이다.

Output

첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.

Example

input

4
0 1 2 3
4 0 5 6
7 1 0 2
3 4 5 0

output

0

Solution & Inpression

N개중 N/2개를 선택하여 2개의 그룹으로 나눈뒤 각각의 그래프의 가중치를 더해 최솟값을 찾는 문제. [BOJ]게리멘더링을 풀기전에 풀어보았더라면 게리멘더링을 더 쉽게 풀었을것 같다.

Code

언어 : JAVA

메모리 : 17,560kb

실행시간 : 336 ms

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int[][] matrix;
    static int[] visit;
    static int min;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        matrix = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                matrix[i][j] = sc.nextInt();
            }
        }
        min = Integer.MAX_VALUE;
        visit = new int[N];
        solve(N, N / 2, 0, 0);
        System.out.println(min);

    }

    static void solve(int n, int r, int depth, int start) {
        if(depth!=0&&visit[0]==0)
            return;
        if (depth == r) {
            int team1 = 0, team2 = 0;
            //System.out.println(Arrays.toString(visit));
            for (int i = 0; i < n; i++) {
                if (visit[i] == 1)
                    for (int j = 0; j < n; j++) {
                        if (i != j && visit[j] == 1)
                            team1 += matrix[i][j];
                    }
                else
                    for (int j = 0; j < n; j++) {
                        if (i != j && visit[j] == 0)
                            team2 += matrix[i][j];
                    }
            }
            int res = Math.abs(team1 - team2);
            if (res < min)
                min = res;
            return;
        }

        for (int i = start; i < n; i++) {
            if (visit[i] == 0) {
                visit[i] = 1;
                solve(n, r, depth + 1, i);
                visit[i] = 0;
            }
        }
    }
}

[BOJ] 14888. 연산자끼워넣기 - Permutation

제출일 : 2019-10-14

문제 풀이 시간 : 1H

난이도 : ★★☆

Problem

link : https://www.acmicpc.net/problem/148989

Input

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다.

Output

첫째 줄에 만들 수 있는 식의 결과의 최댓값을, 둘째 줄에는 최솟값을 출력한다. 최댓값과 최솟값이 항상 -10억보다 크거나 같고, 10억보다 작거나 같은 결과가 나오는 입력만 주어진다. 또한, 앞에서부터 계산했을 때, 중간에 계산되는 식의 결과도 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.

Example

input

4
0 1 2 3
4 0 5 6
7 1 0 2
3 4 5 0

output

0

Solution & Inpression

최대 10!의 경우의 수가 나오기때문에 완전탐색으로 풀어도 가능한 문제로 순열을 이용하여 해결하였다. 입력이 N개의 숫자에 대해 N-1개의 사칙연산의 개수가 주어지는데 이를 N-1크기의 배열로 값을 받았다.

Code

언어 : JAVA

메모리 : 15,140kb

실행시간 : 352 ms

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static boolean[] visit;
    static int[] numbers;
    static int[] op;
    static int n, max, min;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        numbers = new int[n];

        for (int i = 0; i < n; i++)
            numbers[i] = sc.nextInt();

        op = new int[n - 1];
        int idx = 0;
        for (int i = 0; i < 4; i++)
            for (int j = sc.nextInt(); j > 0; j--)
                op[idx++] = i + 1;

        max = Integer.MIN_VALUE;    min = Integer.MAX_VALUE;
        visit = new boolean[n - 1];

        solve(0, 1, numbers[0], 0);
        System.out.println(max);    System.out.println(min);

    }

    public static void solve(int v, int idx, int num, int len) {
        int result = 0;
        if (len == n - 1) {
            if (num > max)    max = num;
            if (num < min)    min = num;
            return;
        }

        for (int i = 0; i < n - 1; i++) {
            if (!visit[i]) {
                visit[i] = true;
                switch (op[i]) {
                case 1:    result = num + numbers[idx];    break;
                case 2:    result = num - numbers[idx];    break;
                case 3:    result = num * numbers[idx];    break;
                case 4:    result = num / numbers[idx];    break;
                }
                solve(i, idx + 1, result, len + 1);
                visit[i] = false;
            }
        }
    }
}

'Problem > BOJ' 카테고리의 다른 글

[BOJ] 14890. 경사로 - Simulation  (0) 2019.10.14
[BOJ] 14889. 스타트와 링크- Permutation  (0) 2019.10.14
[BOJ] 1157. 단어공부 - Array  (0) 2019.10.08
[BOJ] 17472. 다리 만들기2 - Prim  (0) 2019.10.07
[BOJ] 4963. 섬의 개수 - DFS  (0) 2019.10.07

[BOJ] 1157. 단어공부 - Array

제출일 : 2019-10-08

문제 풀이 시간 : 5M

난이도 : ☆

Problem

link : https://www.acmicpc.net/problem/17472

Input

첫째 줄에 알파벳 대소문자로 이루어진 단어가 주어진다. 주어지는 단어의 길이는 1,000,000을 넘지 않는다.

Output

첫째 줄에 이 단어에서 가장 많이 사용된 알파벳을 대문자로 출력한다. 단, 가장 많이 사용된 알파벳이 여러 개 존재하는 경우에는 ?를 출력한다.

Example

input

Mississipi

output

?

Solution & Inpression

알파벳은 26개

Code

언어 : JAVA

메모리 : 32,220 kb

실행시간 : 332 ms

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        char[] arr = sc.next().toUpperCase().toCharArray();

        int[] cnt = new int[26];

        for (int i = 0; i < arr.length; i++) {
            cnt[arr[i]-'A']++;
        }
        int max = -1;
        int maxIdx = -1;
        for (int i = 0; i < cnt.length; i++) {
            if(max<cnt[i]) {
                max = cnt[i];
                maxIdx = i;
            }
        }

        for (int i = 0; i < cnt.length; i++) {
            if(maxIdx!=i) {
                if(max==cnt[i]) {
                    System.out.println("?");
                    return;
                }            
            }
        }

        System.out.println((char)('A'+maxIdx));
    }
}

[BOJ] 17472. 다리 만들기2 - Prim

제출일 : 2019-10-07

문제 풀이 시간 : 45M

난이도 : ★★★★

Problem

link : https://www.acmicpc.net/problem/17472

Input

첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. 둘째 줄부터 N개의 줄에 지도의 정보가 주어진다. 각 줄은 M개의 수로 이루어져 있으며, 수는 0 또는 1이다. 0은 바다, 1은 땅을 의미한다.

Output

모든 섬을 연결하는 다리 길이의 최솟값을 출력한다. 모든 섬을 연결하는 것이 불가능하면 -1을 출력한다.

Example

input

7 8
0 0 0 0 0 0 1 1
1 1 0 0 0 0 1 1
1 1 0 0 0 0 0 0
1 1 0 0 0 1 1 0
0 0 0 0 0 1 1 0
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1

output

9

Solution & Inpression

문제 풀이 순서

1. 섬을 구분한다

섬의 개수를 파악하하고 그래프를 그리기 위해 섬을 분리하는 작업을 진행한다.

BFS를 이용하여 섬을 라벨링 했다.

2. 그래프를 생성한다.

섬의 개수(정점)의 그래프를 생성한다.

3. 생성된 그래프의 간선을 연결한다.

섬을 잇는 간선을 찾아 연결한다. 이때 다리의 길이는 최소 2이상이어야 한다.

4. 최소신장트리를 이용하여 결과 값을 찾는다.

프림 알고리즘을 이용하여 최소신장트리를 구하고 이때의가중치의 합(결과값)을 찾는다.

모든 정점이 연결되지 못할경우 -1을 리턴한다.


삼성 A형 기출문제다 문제가 참 더럽다고 생각한다.

두번째 도전이라 생각보다 시간이 덜 걸렸고 맨처음엔 풀다가 포기했었다.

문제를 풀 순서는 머릿속에 있었지만 간선을 찾지 못했었고, 최소신장트리 알고리즘 또한 아직 익숙지 않았었다.

최소신장트리를 공부하였고 위 문제에 적용하여 해결하였다.

Code

언어 : JAVA

메모리 : 14,396 kb

실행시간 : 108 ms

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    static int N, M, count;
    static int[][] map;
    static int[][] graph;
    static int[] dr = { -1, 1, 0, 0 };
    static int[] dc = { 0, 0, -1, 1 };

    static int[] dist;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();
        map = new int[N][M];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                int tmp = sc.nextInt();
                if (tmp == 1)
                    map[i][j] = -1;
                else
                    map[i][j] = tmp;
            }
        }
        //1. 섬을 분리한다.
        count = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (map[i][j] == -1)
                    BFS(i, j, ++count);
            }
        }
        //2. 그래프를 생성한다.
        graph = new int[count][count];

        for (int i = 0; i < count; i++) {
            for (int j = 0; j < count; j++) {
                if (i == j)
                    continue;
                graph[i][j] = Integer.MAX_VALUE;
            }
        }
        //3. 생성된 그래프의 간선을 연결한다.
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {

                if (map[i][j] != 0) {
                    for (int dir = 0; dir < 4; dir++) {
                        int r = i + dr[dir];
                        int c = j + dc[dir];
                        if (range(r, c)) {
                            if (map[r][c] == 0) {
                                makeGraph(new int[] { i, j }, new int[] { r, c }, dir, 1);
                            }
                        }
                    }
                }
            }
        }

        dist = new int[count];
        System.out.println(prim(graph));

    }

    public static int prim(int[][] graph) {
        Arrays.fill(dist, -1);
        dist[0] = 0;

        for (int k = 0; k < count; k++) {
            int minWeight = Integer.MAX_VALUE;
            int minVertex = 0;

            for (int i = 0; i < count; i++) {
                if (dist[i] < 0)
                    continue;
                for (int j = 0; j < count; j++) {
                    if (dist[j] >= 0)
                        continue;
                    if (minWeight > graph[i][j]) {
                        minWeight = graph[i][j];
                        minVertex = j;
                    }
                }
            }
            dist[minVertex] = minWeight;

        }
        int sum = 0;
        for (int i = 1; i < count; i++) {
            if(dist[i]==-1)
                return -1;
            sum += dist[i];
        }
        return sum;
    }

    private static void makeGraph(int[] start, int[] cur, int dir, int cnt) {
        int r = cur[0] + dr[dir];
        int c = cur[1] + dc[dir];
        if (range(r, c)) {
            if (map[r][c] == 0) {
                makeGraph(start, new int[] { r, c }, dir, ++cnt);
            } else {
                int s = map[start[0]][start[1]] - 1;
                int e = map[r][c] - 1;
                if (cnt >= 2) {
                    if (graph[s][e] > cnt) {
                        graph[s][e] = cnt;
                        graph[e][s] = cnt;
                    }
                }
            }
        }
    }

    private static void BFS(int i, int j, int cnt) {
        Queue<int[]> q = new LinkedList<int[]>();
        q.offer(new int[] { i, j, cnt });
        map[i][j] = cnt;

        while (!q.isEmpty()) {
            int[] tmp = q.poll();
            for (int k = 0; k < 4; k++) {
                int r = tmp[0] + dr[k];
                int c = tmp[1] + dc[k];
                if (range(r, c)) {
                    if (map[r][c] == -1) {
                        q.offer(new int[] { r, c, cnt });
                        map[r][c] = cnt;
                    }
                }
            }
        }
    }
    private static boolean range(int r, int c) {
        if (0 <= r && r < N && 0 <= c && c < M)
            return true;
        return false;
    }
}

'Problem > BOJ' 카테고리의 다른 글

[BOJ] 14888. 연산자끼워넣기 - Permutation  (0) 2019.10.14
[BOJ] 1157. 단어공부 - Array  (0) 2019.10.08
[BOJ] 4963. 섬의 개수 - DFS  (0) 2019.10.07
[BOJ] 4963. 섬의 개수 - BFS  (0) 2019.10.07
[BOJ] 5427. 불 - BFS  (0) 2019.10.06

[BOJ] 4963. 섬의 개수 - DFS

제출일 : 2019-10-07

문제 풀이 시간 : 10M

난이도 : ★

Problem

link : https://www.acmicpc.net/problem/4963

Input

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 지도의 너비 w와 높이 h가 주어진다. w와 h는 50보다 작거나 같은 양의 정수이다.

둘째 줄부터 h개 줄에는 지도가 주어진다. 1은 땅, 0은 바다이다.

입력의 마지막 줄에는 0이 두 개 주어진다.

Output

각 테스트 케이스에 대해서, 섬의 개수를 출력한다.

Example

input

1 1
0
2 2
0 1
1 0
3 2
1 1 1
1 1 1
5 4
1 0 1 0 0
1 0 0 0 0
1 0 1 0 1
1 0 0 1 0
5 4
1 1 1 0 1
1 0 1 0 1
1 0 1 0 1
1 0 1 1 1
5 5
1 0 1 0 1
0 0 0 0 0
1 0 1 0 1
0 0 0 0 0
1 0 1 0 1
0 0

output

0
1
1
3
1
9

Solution & Inpression

DFS의 가장 기본적인 문제

Code

언어 : JAVA

메모리 : 33,252 kb

실행시간 : 312 ms

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

public class Main_백준_4963_섬의개수_DFS {
    static int W, H;
    static int[][] map;

    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        while (true) {
            W = sc.nextInt();
            H = sc.nextInt();

            if (W == 0 && H == 0)
                break;

            map = new int[H][W];

            for (int i = 0; i < H; i++) {
                for (int j = 0; j < W; j++) {
                    int tmp = sc.nextInt();
                    if (tmp == 1)
                        map[i][j] = -1;
                    else
                        map[i][j] = tmp;
                }
            }

            int cnt = 0;
            for (int i = 0; i < H; i++) {
                for (int j = 0; j < W; j++) {
                    if (map[i][j] == -1) {
                        map[i][j] = ++cnt;
                        solve(i, j, cnt);
                    }
                }
            }
            System.out.println(cnt);

            // for (int[] is : map)
            // System.out.println(Arrays.toString(is));

        } // end of tc
        sc.close();
    }// end of main

    private static void solve(int i, int j, int cnt) {
        int[] dr = { -1, 1, 0, 0, 1, 1, -1, -1 };
        int[] dc = { 0, 0, -1, 1, 1, -1, -1, 1 };

        for (int k = 0; k < 8; k++) {
            int r = i + dr[k];
            int c = j + dc[k];
            if (range(r, c)) {
                if (map[r][c] == -1) {
                    map[r][c] = cnt;
                    solve(r, c, cnt);
                }
            }
        }
    }

    private static boolean range(int r, int c) {
        if (0 <= r && r < H && 0 <= c && c < W)
            return true;
        return false;
    }
}

'Problem > BOJ' 카테고리의 다른 글

[BOJ] 1157. 단어공부 - Array  (0) 2019.10.08
[BOJ] 17472. 다리 만들기2 - Prim  (0) 2019.10.07
[BOJ] 4963. 섬의 개수 - BFS  (0) 2019.10.07
[BOJ] 5427. 불 - BFS  (0) 2019.10.06
[BOJ] 6593. 상범빌딩 - BFS  (0) 2019.10.03

[BOJ] 4963. 섬의 개수 - BFS

제출일 : 2019-10-07

문제 풀이 시간 : 30M

난이도 : ★★☆

Problem

link : https://www.acmicpc.net/problem/4963

Input

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 지도의 너비 w와 높이 h가 주어진다. w와 h는 50보다 작거나 같은 양의 정수이다.

둘째 줄부터 h개 줄에는 지도가 주어진다. 1은 땅, 0은 바다이다.

입력의 마지막 줄에는 0이 두 개 주어진다.

Output

각 테스트 케이스에 대해서, 섬의 개수를 출력한다.

Example

input

1 1
0
2 2
0 1
1 0
3 2
1 1 1
1 1 1
5 4
1 0 1 0 0
1 0 0 0 0
1 0 1 0 1
1 0 0 1 0
5 4
1 1 1 0 1
1 0 1 0 1
1 0 1 0 1
1 0 1 1 1
5 5
1 0 1 0 1
0 0 0 0 0
1 0 1 0 1
0 0 0 0 0
1 0 1 0 1
0 0

output

0
1
1
3
1
9

Solution & Inpression

1차 시도 : 메모리 초과

    private static void solve(int i, int j, int cnt) {
        int[] dr = { -1, 1, 0, 0, 1, 1, -1, -1 };
        int[] dc = { 0, 0, -1, 1, 1, -1, -1, 1 };

        Queue<int[]> q = new LinkedList<>();
        q.offer(new int[] { i, j });

        while (!q.isEmpty()) {
            int[] tmp = q.poll();
            map[tmp[0]][tmp[1]] = cnt;

            for (int k = 0; k < 8; k++) {
                int r = tmp[0] + dr[k];
                int c = tmp[1] + dc[k];
                if (range(r, c)) {
                    if (map[r][c] == -1) {
                        q.offer(new int[] { r, c });
                    }
                }
            }
        }
    }

방문처리를 큐에서 값을 빼올때 처리하였다.

이렇게 작성하였다면 이미 큐에 담겨있지만 방문이 안되었다 판단하기 때문에 불필요하게 큐에 값이 들어가게 되는 현상이 발생하여 메모리초과가 발생한다.

방문처리를 아래와 같은 방법으로 수정하여 메모리 초과는 발생하지 않았다.

Code

언어 : JAVA

메모리 : 32,984 kb

실행시간 : 328 ms

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

public class Main_백준_4963_섬의개수 {
    static int W, H;
    static int[][] map;

    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        while (true) {
            W = sc.nextInt();
            H = sc.nextInt();

            if (W == 0 && H == 0)
                break;

            map = new int[H][W];

            for (int i = 0; i < H; i++) {
                for (int j = 0; j < W; j++) {
                    int tmp = sc.nextInt();
                    if (tmp == 1)
                        map[i][j] = -1;
                    else
                        map[i][j] = tmp;
                }
            }

            int cnt = 0;
            for (int i = 0; i < H; i++) {
                for (int j = 0; j < W; j++) {
                    if (map[i][j] == -1) {
                        solve(i, j, ++cnt);
                    }
                }
            }
            System.out.println(cnt);

            // for(int[] is : map)
            // System.out.println(Arrays.toString(is));

        } // end of tc
        sc.close();
    }// end of main

    private static void solve(int i, int j, int cnt) {
        int[] dr = { -1, 1, 0, 0, 1, 1, -1, -1 };
        int[] dc = { 0, 0, -1, 1, 1, -1, -1, 1 };

        Queue<int[]> q = new LinkedList<>();
        q.offer(new int[] { i, j });
        map[i][j] = cnt;

        while (!q.isEmpty()) {
            int[] tmp = q.poll();

            for (int k = 0; k < 8; k++) {
                int r = tmp[0] + dr[k];
                int c = tmp[1] + dc[k];
                if (range(r, c)) {
                    if (map[r][c] == -1) {
                        q.offer(new int[] { r, c });
                        map[r][c] = cnt;
                    }
                }
            }
        }
    }

    private static boolean range(int r, int c) {
        if (0 <= r && r < H && 0 <= c && c < W)
            return true;
        return false;
    }
}

'Problem > BOJ' 카테고리의 다른 글

[BOJ] 1157. 단어공부 - Array  (0) 2019.10.08
[BOJ] 17472. 다리 만들기2 - Prim  (0) 2019.10.07
[BOJ] 4963. 섬의 개수 - DFS  (0) 2019.10.07
[BOJ] 5427. 불 - BFS  (0) 2019.10.06
[BOJ] 6593. 상범빌딩 - BFS  (0) 2019.10.03