문제

최흉최악의 해커 yum3이 네트워크 시설의 한 컴퓨터를 해킹했다! 이제 서로에 의존하는 컴퓨터들은 점차 하나둘 전염되기 시작한다. 어떤 컴퓨터 a가 다른 컴퓨터 b에 의존한다면, b가 감염되면 그로부터 일정 시간 뒤 a도 감염되고 만다. 이때 b가 a를 의존하지 않는다면, a가 감염되더라도 b는 안전하다.

최흉최악의 해커 yum3이 해킹한 컴퓨터 번호와 각 의존성이 주어질 때, 해킹당한 컴퓨터까지 포함하여 총 몇 대의 컴퓨터가 감염되며 그에 걸리는 시간이 얼마인지 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 테스트 케이스의 개수가 주어진다. 테스트 케이스의 개수는 최대 100개이다. 각 테스트 케이스는 다음과 같이 이루어져 있다.

  • 첫째 줄에 컴퓨터 개수 n, 의존성 개수 d, 해킹당한 컴퓨터의 번호 c가 주어진다(1 ≤ n ≤ 10,000, 1 ≤ d ≤ 100,000, 1 ≤ c ≤ n).
  • 이어서 d개의 줄에 각 의존성을 나타내는 정수 a, b, s가 주어진다(1 ≤ a, b ≤ n, a ≠ b, 0 ≤ s ≤ 1,000). 이는 컴퓨터 a가 컴퓨터 b를 의존하며, 컴퓨터 b가 감염되면 s초 후 컴퓨터 a도 감염됨을 뜻한다.

각 테스트 케이스에서 같은 의존성 (a, b)가 두 번 이상 존재하지 않는다.

 

출력

각 테스트 케이스마다 한 줄에 걸쳐 총 감염되는 컴퓨터 수, 마지막 컴퓨터가 감염되기까지 걸리는 시간을 공백으로 구분지어 출력한다.

 

예제

 

풀이 방법

해커로부터 컴퓨터를 해킹해 서로 의존하는 컴퓨터들이 모두 감염되는 시간과, 감염된 컴퓨터의 수를 구하는 문제였습니다.

 

저는 배열과 리스트 두 가지 방식으로 다익스트라 알고리즘을 이용해 문제를 해결했습니다.

 

1) 연결되어 있는 컴퓨터 정보 배열/리스트에 저장

2) 컴퓨터간의 감염시간을 저장할 distance 배열 큰 수로 초기화

3) 다익스트라 알고리즘을 이용해 최소 감염시간 distance배열에 저장

4) 감염되는 시간 및 감염된 컴퓨터 수를 구하기 위해 distance배열 값이 INF가 아닌 경우 count++ 및 distance 최댓값 구하기

5) count 및 최대 distance 값 출력

 

코드 (배열)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
 
public class Main_BJ_10282_해킹_array {
    
    static class info{
        int end, time;
 
        public info(int end, int time) {
            super();
            this.end = end;
            this.time = time;
        }
 
    }
    
    static int INF = Integer.MAX_VALUE;
    static boolean[] visited;
    static List<info> list[];
    static int [] distance;
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st;
        
        int T = Integer.parseInt(br.readLine());
        
        for(int tc=0; tc<T;tc++) {
            st = new StringTokenizer(br.readLine());
            int n = Integer.parseInt(st.nextToken());
            int d = Integer.parseInt(st.nextToken());
            int c = Integer.parseInt(st.nextToken());
            
            list = new ArrayList[n+1];
            distance = new int[n+1];
            visited = new boolean[n+1];
            
            for(int i=1;i<=n;i++) list[i] = new ArrayList<>();
            
            for(int i=0;i<d;i++) {
                st = new StringTokenizer(br.readLine());
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());
                int s = Integer.parseInt(st.nextToken());
                
                list[b].add(new info(a,s));
            }
            
            Arrays.fill(distance, INF);
            distance[c]=0;
            
            int min, current = 0;
            for(int i=0; i<n;i++) {
                min = Integer.MAX_VALUE;
                current = -1;
                for(int j=1;j<n+1;j++) {
                    if(!visited[j] && distance[j]<min) {
                        min = distance[j];
                        current =j;
                    }
                }
                if(current == -1break;
                
                for(info next : list[current]) {
                    if(!visited[next.end] && distance[next.end]> distance[current]+next.time) {
                        distance[next.end] = distance[current] + next.time;
                    }
                }
                visited[current] = true;
            }
            
            int count=0, max=0;
            for(int i=1;i<distance.length;i++) {
                if(distance[i]!=INF) {
                    count++;
                    max = Math.max(max, distance[i]);
                }
                
            }
            sb.append(count+" "+max+"\n");
        }
        System.out.println(sb.toString());
    }
 
}
cs

 

코드 (리스트)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
 
public class Main_BJ_10282_해킹_list {
    
    static class info{
        int end, time;
 
        public info(int end, int time) {
            super();
            this.end = end;
            this.time = time;
        }
 
    }
    
    static int INF = Integer.MAX_VALUE;
    static boolean[] visited;
    static ArrayList<ArrayList<info>> list;
    static int [] distance;
    static PriorityQueue<info> pq = new PriorityQueue<>(new Comparator<info>() {
 
        @Override
        public int compare(info o1, info o2) {
            return o1.time-o2.time;
        }
    });
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st;
        
        int T = Integer.parseInt(br.readLine());
        
        for(int tc=0; tc<T;tc++) {
            st = new StringTokenizer(br.readLine());
            int n = Integer.parseInt(st.nextToken());
            int d = Integer.parseInt(st.nextToken());
            int c = Integer.parseInt(st.nextToken());
            
            list = new ArrayList<>();
            distance = new int[n+1];
            visited = new boolean[n+1];
            
            for(int i=0;i<=n;i++) list.add(new ArrayList<>());
            
            for(int i=0;i<d;i++) {
                st = new StringTokenizer(br.readLine());
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());
                int s = Integer.parseInt(st.nextToken());
                
                list.get(b).add(new info(a,s));
            }
            
            Arrays.fill(distance, INF);
            
            distance[c]=0;
            
            pq.add(new info(c,0));
            while(!pq.isEmpty()) {
                info temp = pq.poll();
                if(visited[temp.end]) continue;
                visited[temp.end]= true;
                
                for(info node : list.get(temp.end)) {
                    if(distance[node.end]>distance[temp.end]+node.time) {
                        distance[node.end] = distance[temp.end]+node.time;
                        pq.add(new info(node.end,distance[node.end]));
                    }
                }
            }
            
            
            int count=0, max=0;
            for(int i=1;i<distance.length;i++) {
                if(distance[i]!=INF) {
                    count++;
                    max = Math.max(max, distance[i]);
                }
                
            }
            sb.append(count+" "+max+"\n");
        }
        System.out.println(sb.toString());
    }
 
}
cs

 

 

문제

식재료 N개 중에서 몇 개를 선택해서 이들의 영양분(단백질, 탄수화물, 지방, 비타민)이 일정 이상이 되어야 한다. 아래 표에 제시된 6가지의 식재료 중에서 몇 개를 선택해서 이들의 영양분의 각각 합이 최소 100, 70, 90, 10가 되도록 하는 경우를 생각해보자. 이 경우 모든 재료를 선택하면 쉽게 해결되지만, 우리는 조건을 만족시키면서도 비용이 최소가 되는 선택을 하려고 한다.

재료 단백질 지방 탄수화물 비타민 가격

1 30 55 10 8 100
2 60 10 10 2 70
3 10 80 50 0 50
4 40 30 30 8 60
5 60 10 70 2 120
6 20 70 50 4 40

예를 들어, 식재료 1, 3, 5를 선택하면 영양분은 100, 145, 130, 10으로 조건을 만족하지만 가격은 270이 된다. 대신 2, 3, 4를 선택하면 영양분의 합은 110, 130, 90, 10, 비용은 180이 되므로, 앞의 방법보다는 더 나은 선택이 된다.

입력으로 식재료 표가 주어졌을 때, 최저 영양소 기준을 만족하는 최소 비용의 식재료 집합을 찾아야 한다.

 

입력

첫 줄에 식재료의 개수 N이 주어진다.

다음 줄에는 단백질, 지방, 탄수화물, 비타민의 최소 영양성분을 나타내는 정수 mp, mf, ms, mv가 주어진다.

이어지는 N개의 각 줄에는 i번째 식재료의 단백질, 지방, 탄수화물, 비타민과 가격이 5개의 정수 pi, fi, si, vi, ci와 같이 주어진다. 식재료의 번호는 1부터 시작한다.

 

출력

첫 번째 줄에 최소 비용을 출력하고, 두 번째 줄에 조건을 만족하는 최소 비용 식재료의 번호를 공백으로 구분해 오름차순으로 한 줄에 출력한다. 같은 비용의 집합이 하나 이상이면 사전 순으로 가장 빠른 것을 출력한다.

조건을 만족하는 답이 없다면 -1을 출력하고, 둘째 줄에 아무것도 출력하지 않는다.

 

예제

 

풀이 방법

선택한 식재료들의 영양분 합이 최저 영양소 기준을 만족하면서 최소 비용의 식재료의 집합을 찾는 문제였습니다.

 

일단 먼저, 만족하는 집합을 찾기 위해 식재료를 최소 1개 이상 최대 N개 이하를 선택할 수 있기 때문에 반복문을 통해 해당 식재료 개수만큼 선택하여 그 선택된 식재료의 영양분 합이 최저 영양소의 기준을 만족하나 확인해 주었습니다.

isCheck() 메서드에서 선택한 식재료들의 영양분의 합들을 sum배열에 넣어준 뒤, 하나라도 최저 영양소 기준을 만족하지 못한다면 false를 리턴해주고 이외에는 선택된 식재료들의 가격을 비교하여 최소 비용의 식재료의 집합을 찾아주었습니다. 

 

출력 조건이 같은 비용의 집합이 하나 이상이면 사전 순으로 가장 빠른 것을 출력해야 하기 때문에, list에 넣어 정렬을 한 뒤 가장 첫 번째 리스트의 값을 출력해주었습니다. 만약 조건을 만족하는 집합이 없다면 -1을 출력해주었습니다. 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;
 
public class Main_BJ_19942_다이어트 {
    
    static int N, M=5,ans =Integer.MAX_VALUE;
    static int [][] nutrients;
    static int [] minN;
    static int []select;
    
    static ArrayList<String> list = new ArrayList<>();
    
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        N = Integer.parseInt(br.readLine());
        
        nutrients = new int[N][M]; // N개의 영양분을 담을 배열
        minN = new int[4]; // 최저 영양소 기준을 담을 배열
        
        st = new StringTokenizer(br.readLine());
        for(int i=0;i<4;i++) minN[i] = Integer.parseInt(st.nextToken());
        
        for(int i=0;i<N;i++) {
            st = new StringTokenizer(br.readLine());
            for(int j=0;j<M;j++) {
                nutrients[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        for(int i=1;i<=N;i++) {
            select = new int[N];
            choice(0,i,0);
        }
        if(list.size()>0) {
            System.out.println(ans);
            Collections.sort(list);
            String st1 = list.get(0);
            for(int i=0;i<st1.length();i++) {
                System.out.print(st1.charAt(i));
            }
        }else System.out.println(-1);
    }
    
    public static void choice(int cnt, int sel, int start) {
        if(cnt==sel) {
           isCheck(sel); //조건체크
            return;
        }
        for(int i=start;i<N;i++) {
                select[cnt]=i;
                choice(cnt+1,sel,i+1);
        }
        
    }
    
    public static boolean isCheck(int sel) {
        int price=0;
        int []sum = new int[4];
        for(int i=0;i<sel;i++) {
                sum[0]+=nutrients[select[i]][0];
                sum[1]+=nutrients[select[i]][1];
                sum[2]+=nutrients[select[i]][2];
                sum[3]+=nutrients[select[i]][3];
                price+=nutrients[select[i]][4];            
        }
        
        for(int i=0;i<4;i++) {
            if(minN[i]>sum[i]) return false;
        }
        
        if(ans>=price) {
            if(ans>price) {
                list.clear();
            }
            String str="";
            for(int i=0;i<sel;i++) {
                str+=(select[i]+1+" ");
            }
            list.add(str);
            ans = price;
        }
        return true;
    }
}
cs

 

'문제 > 백준' 카테고리의 다른 글

백준 2252번 줄세우기 [JAVA]  (0) 2021.06.18
백준 10282번 해킹 [JAVA]  (0) 2021.06.17
백준 5014번 스타트링크 [JAVA]  (0) 2021.06.16
백준 9207번 페그 솔리테어 [JAVA]  (0) 2021.06.15
백준 17143번 낚시왕 [JAVA]  (0) 2021.06.15

문제

강호는 코딩 교육을 하는 스타트업 스타트링크에 지원했다. 오늘은 강호의 면접날이다. 하지만, 늦잠을 잔 강호는 스타트링크가 있는 건물에 늦게 도착하고 말았다.

스타트링크는 총 F층으로 이루어진 고층 건물에 사무실이 있고, 스타트링크가 있는 곳의 위치는 G층이다. 강호가 지금 있는 곳은 S층이고, 이제 엘리베이터를 타고 G층으로 이동하려고 한다.

보통 엘리베이터에는 어떤 층으로 이동할 수 있는 버튼이 있지만, 강호가 탄 엘리베이터는 버튼이 2개밖에 없다. U버튼은 위로 U층을 가는 버튼, D버튼은 아래로 D층을 가는 버튼이다. (만약, U층 위, 또는 D층 아래에 해당하는 층이 없을 때는, 엘리베이터는 움직이지 않는다)

강호가 G층에 도착하려면, 버튼을 적어도 몇 번 눌러야 하는지 구하는 프로그램을 작성하시오. 만약, 엘리베이터를 이용해서 G층에 갈 수 없다면, "use the stairs"를 출력한다.

 

입력

첫째 줄에 F, S, G, U, D가 주어진다. (1 ≤ S, G ≤ F ≤ 1000000, 0 ≤ U, D ≤ 1000000) 건물은 1층부터 시작하고, 가장 높은 층은 F층이다.

 

출력

첫째 줄에 강호가 S층에서 G층으로 가기 위해 눌러야 하는 버튼의 수의 최솟값을 출력한다. 만약, 엘리베이터로 이동할 수 없을 때는 "use the stairs"를 출력한다.

 

예제

 

풀이 방법

S층에서 G층으로 가기 위해 눌러야 하는 최소한의 버튼 수를 구하는 문제였습니다.

 

먼저 현재 위치를 우선순위 큐에 넣어주었습니다. 현재 위치가 도착 층수인 G층 이라면 우선순위 큐에 같이 넣어주었던 누른 버튼의 수를 출력하면서 반복문을 종료하고, 그 외에 경우에 위로 U층만큼, 아래로 D층만큼 이동하면서 만약 한 번도 도착하지 않았던 층수라면 도착했다고 표시해주고 큐에 해당 위치 정보를 넣어주었습니다. 만약 큐에 아무것도 없어 반복문이 종료되었고, 도착하고자 하는 층수에 도착했는지를 확인해주는 flag변수를 통해 flag가 false라면 도착 층수에 도달하지 못한다는 의미이므로 use the stairs를 출력해주었습니다.

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
 
public class Main_BJ_5014_스타트링크 {
    
    static class info implements Comparable<info>{
        int floor, check;
 
        public info(int floor, int check) {
            super();
            this.floor = floor;
            this.check = check;
        }
 
        @Override
        public int compareTo(info o) {
            return this.check-o.check;
        }
        
    }
    
    static int F,S,G,U,D;
    static int [] map;
    static PriorityQueue<info> queue = new PriorityQueue<>();
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
        
        F = Integer.parseInt(st.nextToken()); //층 총수
        S = Integer.parseInt(st.nextToken()); // 현재 층수
        G = Integer.parseInt(st.nextToken()); // 도착 층수
        U = Integer.parseInt(st.nextToken()); //위로 U만큼
        D = Integer.parseInt(st.nextToken()); //아래로 D만큼
        
        map = new int[F+1];
        
        queue.add(new info(S,0));
        
        int [] dx = {U,-D};
        boolean flag = false;
        while(!queue.isEmpty()) {
            info now = queue.poll();
            
            
            if(now.floor==G) {
                flag=true;
                System.out.println(now.check);
                break;
            }
            
            for(int i=0;i<2;i++) {
                int nx = now.floor+dx[i];
                if(range(nx) && map[nx]==0) {
                    map[nx]=1;
                    queue.add(new info(nx,now.check+1));
                }
            }
        }
        if(!flag) System.out.println("use the stairs");
        
    }
    
    public static boolean range(int x) {
        return x>=1 && x<=F;
    }
 
}
cs

 

 

 

'문제 > 백준' 카테고리의 다른 글

백준 10282번 해킹 [JAVA]  (0) 2021.06.17
백준 19942 다이어트 [JAVA]  (0) 2021.06.16
백준 9207번 페그 솔리테어 [JAVA]  (0) 2021.06.15
백준 17143번 낚시왕 [JAVA]  (0) 2021.06.15
백준 16235번 나무 재테크 [JAVA]  (0) 2021.06.11

문제

페그 솔리테어는 구멍이 뚫려있는 이차원 게임판에서 하는 게임이다. 각 구멍에는 핀을 하나 꽂을 수 있다.

핀은 수평, 수직 방향으로 인접한 핀을 뛰어넘어서 그 핀의 다음 칸으로 이동하는 것만 허용된다. 인접한 핀의 다음 칸은 비어있어야 하고 그 인접한 핀은 제거된다.

현재 게임판에 꽂혀있는 핀의 상태가 주어진다. 이때, 핀을 적절히 움직여서 게임판에 남아있는 핀의 개수를 최소로 하려고 한다. 또, 그렇게 남기기 위해 필요한 최소 이동횟수를 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 테스트 케이스의 개수 1 ≤ N ≤ 100이 주어진다. 각 테스트 케이스는 게임판의 초기 상태이다.

게임판은 모두 같은 모양을 가진다. (예제 참고) '.'는 빈 칸, 'o'는 핀이 꽂혀있는 칸, '#'는 구멍이 없는 칸이다. 핀의 개수는 최대 8이며, 각 테스트 케이스는 빈 줄로 구분되어져 있다.

 

출력

각 테스트 케이스에 대해서, 핀을 움직여서 남길 수 있는 핀의 최소 개수와 그 개수를 만들기 위해 필요한 최소 이동 횟수를 출력한다.

 

예제

풀이 방법

핀을 적절히 움직여서 게임판에 남아있는 핀의 개수를 최소로하는 동시에, 최소로 남기기 위해 필요한 최소 이동 횟수를 구하는 문제였습니다. 

 

게임판의 존재하는 핀의 개수를 카운트해주고, remainPin 변수에 핀의 개수를 넣어주었습니다. 게임판의 해당 위치가 핀이 꽂혀있는 칸이라면 dfs() 메서드를 통해 현재 위치의 다음 위치가 게임판의 범위를 넘지 않으면서 핀이 꽂혀있는 칸이고 그 다다음 칸이 빈칸이라면 해당 위치의 핀을 이동할 수 있으므로, 이동시켜주고 핀의 개수를 하나 줄이고, 움직인 수를 하나 늘린 뒤, 다음 게임판에서 핀이 꽂혀있는 위치를 찾은 뒤 위에 과정을 반복해주었습니다. 과정이 끝난 후, 마지막으로 남아있는 핀의 개수와, 이동 횟수를 출력해주었습니다.

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main_BJ_9207_페그솔리테어 {
    
    static char [][] map;
    static int xx=5,yy=9,remainPin, move;
    
    static int [] dx = {-1,0,1,0};
    static int [] dy = {0,1,0,-1};
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        
        int T = Integer.parseInt(br.readLine());
        
        for(int tc=0; tc<T;tc++) {
            map = new char[xx][yy];
            
            int pin=0;
            for(int i=0;i<xx;i++) {
                String str = br.readLine();
                for(int j=0;j<yy;j++) {
                    map[i][j] = str.charAt(j);
                    if(map[i][j]=='o') pin++;
                }
            }
            
            remainPin = pin;
            
            for(int i=0;i<xx;i++) {
                for(int j=0;j<yy;j++) {
                    if(map[i][j]=='o') dfs(i,j,pin,0);
                }
            }
            
            br.readLine();
            
            sb.append(remainPin+" "+move+"\n");
        }
        
        System.out.println(sb.toString());
 
    }
    
    public static void dfs(int x, int y , int remain, int moveCnt) {
        if(remain<=remainPin) {
            remainPin = remain;
            move = moveCnt;
        }
        
        for(int d=0;d<4;d++) {
            int nx = x + dx[d];
            int ny = y + dy[d];
            
            if(range(nx,ny) && map[nx][ny]=='o') {
                int nnx = nx +dx[d];
                int nny = ny +dy[d];
                
                if(range(nnx,nny) && map[nnx][nny]=='.') {
                    map[x][y]=map[nx][ny]='.';
                    map[nnx][nny]='o';
                    
                    for(int i=0;i<xx;i++) {
                        for(int j=0;j<yy;j++) {
                            if(map[i][j]=='o') dfs(i,j,remain-1,moveCnt+1);
                        }
                    }
                    
                    map[x][y]=map[nx][ny]='o';
                    map[nnx][nny]='.';
                }
            }
            
        }
    }
    
    public static boolean range(int x, int y) {
        return x>=0 && x<xx && y>=0 && y<yy;
    }
 
}
cs

문제

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다. 칸에는 상어가 최대 한 마리 들어있을 수 있다. 상어는 크기와 속도를 가지고 있다.

낚시왕은 처음에 1번 열의 한 칸 왼쪽에 있다. 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다. 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하면 이동을 멈춘다.

  1. 낚시왕이 오른쪽으로 한 칸 이동한다.
  2. 낚시왕이 있는 열에 있는 상어 중에서 땅과 제일 가까운 상어를 잡는다. 상어를 잡으면 격자판에서 잡은 상어가 사라진다.
  3. 상어가 이동한다.

상어는 입력으로 주어진 속도로 이동하고, 속도의 단위는 칸/초이다. 상어가 이동하려고 하는 칸이 격자판의 경계를 넘는 경우에는 방향을 반대로 바꿔서 속력을 유지한채로 이동한다.

왼쪽 그림의 상태에서 1초가 지나면 오른쪽 상태가 된다. 상어가 보고 있는 방향이 속도의 방향, 왼쪽 아래에 적힌 정수는 속력이다. 왼쪽 위에 상어를 구분하기 위해 문자를 적었다.

상어가 이동을 마친 후에 한 칸에 상어가 두 마리 이상 있을 수 있다. 이때는 크기가 가장 큰 상어가 나머지 상어를 모두 잡아먹는다.

낚시왕이 상어 낚시를 하는 격자판의 상태가 주어졌을 때, 낚시왕이 잡은 상어 크기의 합을 구해보자.

 

입력

첫째 줄에 격자판의 크기 R, C와 상어의 수 M이 주어진다. (2 ≤ R, C ≤ 100, 0 ≤ M ≤ R×C)

둘째 줄부터 M개의 줄에 상어의 정보가 주어진다. 상어의 정보는 다섯 정수 r, c, s, d, z (1 ≤ r ≤ R, 1 ≤ c ≤ C, 0 ≤ s ≤ 1000, 1 ≤ d ≤ 4, 1 ≤ z ≤ 10000) 로 이루어져 있다. (r, c)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다. d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽을 의미한다.

두 상어가 같은 크기를 갖는 경우는 없고, 하나의 칸에 둘 이상의 상어가 있는 경우는 없다.

 

출력

낚시왕이 잡은 상어 크기의 합을 출력한다.

 

예제

 

풀이 방법

낚시왕이 왼쪽에서 오른쪽으로 한칸씩 이동하면서 잡은 상어의 크기의 합을 구하는 문제였습니다.

 

이 낚시왕 문제는 한달전에 시도했으나 틀린 부분을 찾지 못하여 이번에 다시 풀게 되었습니다.

먼저, 이 문제에서

1. 낚시왕 오른쪽으로 한 칸 이동

2. 낚시왕이 있는 해당 열에서 땅과 가장 가까운 상어 잡기, 격자판에서 해당  상어 제거

3. 상어 이동

이라는 세 가지의 과정이 있습니다.

 

첫 번째로 for문을 이용해 낚시왕의 위치를 한 칸씩 이동해 준 뒤, sharkCatch() 메서드를 통해 해당 열에서 가장 가까운 위치에 있는 상어를 잡았습니다. 이동하면서 잡은 상어의 크기의 합을 담아둘 ans변수에 잡은 상어의 크기 값을 넣어주고 격자판에서 해당 상어를 제거해주었습니다. 마지막으로 상어들이 이동하는 sharkMove() 메서드에서 변경된 상어들의 위치를 일시적으로 담아두기 위해 격자판과 동일한 크기의 copy배열을 사용해 움직인 상어들의 위치를 찍어주었습니다. 해당 스피드만큼 상어가 이동한 후, 이동한 상어 위치에 다른 상어가 없다면 배열에 해당 상어 정보를 넣어주고, 움직인 상어가 기존의 있던 상어보다 크기가 큰 경우 기존에 있던 상어는 사라지고 움직인 상어의 정보를 배열에 넣어주었습니다. 반대로 이동한 상어가 기존의 있던 상어보다 크기가 작은 경우 그 상어는 해당 위치에 존재할 수 없으므로 상어 정보를 remove 큐에 넣어주었습니다. 모든 상어들의 이동이 끝난 후, 상어들의 정보가 담겨있는 list과 비교해서 제거될 상어들의 정보를 제거해 준 뒤, 원래 격자판인 map 배열에 상어들이 이동하고 난 뒤의 위치를 복사해 넣어주었습니다.

이 과정을 낚시왕이 왼쪽에서 오른쪽으로 이동할 때까지 반복하여 잡은 상어의 크기를 출력해주었습니다.

 

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
 
 
public class Main_BJ_17143_낚시왕 {
    
    static class info{
        int x,y,speed,dir,size;
 
        public info(int x, int y, int speed, int dir, int size) {
            super();
            this.x = x;
            this.y = y;
            this.speed = speed;
            this.dir = dir;
            this.size = size;
        }
    }
    
    static int R,C,M, ans=0;
    static int [][] map, copy;
    static int [] dx = {0,-1,1,0,0};
    static int [] dy = {0,0,0,1,-1};
    
    static ArrayList<info> shark = new ArrayList<>();
    static Queue<Integer> remove = new LinkedList<>();
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
        R = Integer.parseInt(st.nextToken()); //X
        C = Integer.parseInt(st.nextToken()); //Y
        M = Integer.parseInt(st.nextToken()); //상어 수
        
        map = new int[R+1][C+1];
        
        for(int i=0;i<M;i++) {
            st = new StringTokenizer(br.readLine());
            int r = Integer.parseInt(st.nextToken());
            int c = Integer.parseInt(st.nextToken());
            int s = Integer.parseInt(st.nextToken());
            int d = Integer.parseInt(st.nextToken());
            int z = Integer.parseInt(st.nextToken());
            
            shark.add(new info(r,c,s,d,z));
            map[r][c] = z;
        }
        
        
        for(int i=1;i<=C;i++) {
            //상어잡기
            sharkCatch(i);
            //상어움직이기
            sharkMove();    
        }
        System.out.println(ans);
 
    }
    
    public static void print() {
        for(int i=1;i<R+1;i++) {
            for(int j=1;j<C+1;j++) {
                System.out.print(map[i][j]+" ");
            }
            System.out.println();
        }
    }
    
    public static void sharkCatch(int y) {
        Loop:
        for(int x=1;x<R+1;x++) {
            if(map[x][y]!=0) {
                for(int i=0;i<shark.size();i++) {
                    if(shark.get(i).x==&& shark.get(i).y==y) {
                        ans+=shark.get(i).size;
                        map[x][y]=0;
                        shark.remove(i);
                        break Loop;
                    }
                }
            }
        }
    }
    
    public static void sharkMove() {
        
        copy = new int[R+1][C+1];
        
        for (int i=0;i<shark.size();i++) {
            info temp = shark.get(i);
            
            map[temp.x][temp.y] = 0;
            
            for (int j = 0; j < temp.speed ; j++) {// d==1 상, d==2 하, d==3 우, d==4 좌
 
                if (temp.dir == 1 && temp.x == 1) temp.dir = 2;
                else if (temp.dir == 2 && temp.x == R)temp.dir = 1;
                else if (temp.dir == 3 && temp.y == C)temp.dir = 4;
                else if (temp.dir == 4 && temp.y == 1)temp.dir = 3;
 
                temp.x += dx[temp.dir];
                temp.y += dy[temp.dir];
            } //상어 이동 끝
            
            if(copy[temp.x][temp.y]==0) {
                copy[temp.x][temp.y] = temp.size;
            }else if(copy[temp.x][temp.y]<temp.size) { //움직인 상어가 기존에 있던 상어보다 큰 경우
                remove.add(copy[temp.x][temp.y]);
                copy[temp.x][temp.y] = temp.size;
            }else {
                remove.add(temp.size);
            }
        }
        
        while(!remove.isEmpty()) {
            int temp = remove.poll();
            for(int i=0;i<shark.size();i++) {
                if(temp==shark.get(i).size) {
                    shark.remove(i); break;
                }
            }
        }
        map = copy;
    }
 
}
cs

문제

부동산 투자로 억대의 돈을 번 상도는 최근 N×N 크기의 땅을 구매했다. 상도는 손쉬운 땅 관리를 위해 땅을 1×1 크기의 칸으로 나누어 놓았다. 각각의 칸은 (r, c)로 나타내며, r은 가장 위에서부터 떨어진 칸의 개수, c는 가장 왼쪽으로부터 떨어진 칸의 개수이다. r과 c는 1부터 시작한다.

상도는 전자통신공학과 출신답게 땅의 양분을 조사하는 로봇 S2D2를 만들었다. S2D2는 1×1 크기의 칸에 들어있는 양분을 조사해 상도에게 전송하고, 모든 칸에 대해서 조사를 한다. 가장 처음에 양분은 모든 칸에 5만큼 들어있다.

매일 매일 넓은 땅을 보면서 뿌듯한 하루를 보내고 있던 어느 날 이런 생각이 들었다.

나무 재테크를 하자!

나무 재테크란 작은 묘목을 구매해 어느정도 키운 후 팔아서 수익을 얻는 재테크이다. 상도는 나무 재테크로 더 큰 돈을 벌기 위해 M개의 나무를 구매해 땅에 심었다. 같은 1×1 크기의 칸에 여러 개의 나무가 심어져 있을 수도 있다.

이 나무는 사계절을 보내며, 아래와 같은 과정을 반복한다.

봄에는 나무가 자신의 나이만큼 양분을 먹고, 나이가 1 증가한다. 각각의 나무는 나무가 있는 1×1 크기의 칸에 있는 양분만 먹을 수 있다. 하나의 칸에 여러 개의 나무가 있다면, 나이가 어린 나무부터 양분을 먹는다. 만약, 땅에 양분이 부족해 자신의 나이만큼 양분을 먹을 수 없는 나무는 양분을 먹지 못하고 즉시 죽는다.

여름에는 봄에 죽은 나무가 양분으로 변하게 된다. 각각의 죽은 나무마다 나이를 2로 나눈 값이 나무가 있던 칸에 양분으로 추가된다. 소수점 아래는 버린다.

가을에는 나무가 번식한다. 번식하는 나무는 나이가 5의 배수이어야 하며, 인접한 8개의 칸에 나이가 1인 나무가 생긴다. 어떤 칸 (r, c)와 인접한 칸은 (r-1, c-1), (r-1, c), (r-1, c+1), (r, c-1), (r, c+1), (r+1, c-1), (r+1, c), (r+1, c+1) 이다. 상도의 땅을 벗어나는 칸에는 나무가 생기지 않는다.

겨울에는 S2D2가 땅을 돌아다니면서 땅에 양분을 추가한다. 각 칸에 추가되는 양분의 양은 A[r][c]이고, 입력으로 주어진다.

K년이 지난 후 상도의 땅에 살아있는 나무의 개수를 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 N, M, K가 주어진다.

둘째 줄부터 N개의 줄에 A배열의 값이 주어진다. r번째 줄의 c번째 값은 A[r][c]이다.

다음 M개의 줄에는 상도가 심은 나무의 정보를 나타내는 세 정수 x, y, z가 주어진다. 처음 두 개의 정수는 나무의 위치 (x, y)를 의미하고, 마지막 정수는 그 나무의 나이를 의미한다.

 

출력

첫째 줄에 K년이 지난 후 살아남은 나무의 수를 출력한다.

 

예제

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
 
public class Main_BJ_16235_나무재테크2 {
    
    static class tree {
        int x, y, age;
 
        public tree(int x, int y, int age) {
            super();
            this.x = x;
            this.y = y;
            this.age = age;
        }
    }
    
    static int N,M,K;
    static int [][] land ,add;
    static int [] dx = {-1,-1,-1,0,1,1,1,0};
    static int [] dy = {-1,0,1,1,1,0,-1,-1};
    
    static Queue<tree> live, die;
    static PriorityQueue<tree> pq = new PriorityQueue<>(new Comparator<tree>() {
        @Override
        public int compare(tree o1, tree o2) {
            return o1.age-o2.age;
        }
    });
    
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
        
        N = Integer.parseInt(st.nextToken()); // 땅 크기
        M = Integer.parseInt(st.nextToken()); // 나무 개수
        K = Integer.parseInt(st.nextToken()); // ~년
        
        land = new int[N][N];
        add = new int[N][N];
        
        live = new LinkedList<>();
        die = new LinkedList<>();
        
        for(int i=0;i<N;i++) Arrays.fill(land[i], 5);
        
        for(int i=0;i<N;i++) {
            st = new StringTokenizer(br.readLine());
            for(int j=0;j<N;j++) {
                add[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        
        for(int i=0;i<M;i++) {
            st = new StringTokenizer(br.readLine());
            
            int x = Integer.parseInt(st.nextToken())-1;
            int y = Integer.parseInt(st.nextToken())-1;
            int age = Integer.parseInt(st.nextToken());
            pq.add(new tree(x,y,age));
        }
        
        
        for(int i=0;i<K;i++) {
            spring();
            summer();
            fall();
            winter();
        }
        System.out.println(pq.size());
 
    }
    
    public static void spring() {
        int size = pq.size();
        
        for(int i=0;i<size;i++) {
            tree info = pq.poll();
            if(land[info.x][info.y]>=info.age) {
                land[info.x][info.y]-=info.age;
                live.add(new tree(info.x,info.y,info.age+1));
            }else die.add(info);
        }
    }
    
    public static void summer() {
        int size = die.size();
        
        for(int i=0;i<size;i++) {
            tree info = die.poll();
            land[info.x][info.y]+=info.age/2;
        }
    }
    
    public static void fall() {
        int size = live.size();
        
        for(int i=0;i<size;i++) {
            tree info = live.poll();
            if(info.age%5==0) {
                for(int d=0;d<8;d++) {
                    int nx = info.x+dx[d];
                    int ny = info.y+dy[d];
                    if(range(nx,ny)) pq.add(new tree(nx,ny,1));
                }
            }
            pq.add(info);
        }
    }
    
    public static boolean range(int x, int y) {
        return x>=0 && x<&& y>=0 && y<N;
    }
    
    public static void winter() {
        for(int i=0;i<N;i++) {
            for(int j=0;j<N;j++) {
                land[i][j]+=add[i][j];
            }
        }
    }
}
cs

 

풀이 방법

K 년이 지난 후 땅에 살아있는 나무의 개수를 구하는 문제였습니다.

봄 : 자신의 나이만큼 양분 먹고 나이 +1 (땅에 여러 개의 나무가 있다면 나이가 어린 나무부터 양분 먹기 / 양분이 부족해 나이만큼 양분을 먹을 수 없다면 즉시 죽는다)

여름 : 봄에 죽은 나무의 나이 / 2 만큼 양분+

가을 : 나무의 나이가 5의 배수인 나무는 인접한 8개의 칸에 나이가 1인 나무들 번식

겨울 : 땅에 양분 추가

 

봄에는 나이가 어른 나무부터 양분을 먹어야 하기 때문에 나무의 정보를 나이를 기준으로 정렬하여 우선순위 큐에 넣어주었습니다. 나무가 양분을 먹을 수 있다면 live큐에 나이+1를 해준 나무의 정보를 넣어주고, 만약 양분이 부족하다면 나무는 즉시 죽으므로 die큐에 나무의 정보를 넣어주었습니다. 여름에는 죽은 나무의 나이/2 만큼 양분을 더해주고, 가을에는 나무의 나이가 5의 배수라면 인접한 8개의 칸에 나이가 1인 나무들을 번식할 수 있으므로 pq에 넣어주었습니다. pq에 넣어준 이유는 사계절이 지나 다시 봄이온다면 나이가 적은 나무부터 양분을 먹어야하기 때문에 나이순으로 나무 정보를 우선순위 큐인 pq에 넣어주었습니다. 겨울에는 입력된 양분을 땅에 추가해주었습니다. 이 과정을 K 년 반복 후, 살아있는 나무의 개수를 출력해주었습니다.

 

문제

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다.

만약에 이동하는 도중에 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 K개 까지 부수고 이동하여도 된다.

한 칸에서 이동할 수 있는 칸은 상하좌우로 인접한 칸이다.

맵이 주어졌을 때, 최단 경로를 구해 내는 프로그램을 작성하시오.

 

입력

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

 

출력

첫째 줄에 최단 거리를 출력한다. 불가능할 때는 -1을 출력한다.

 

예제

 

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
 
public class Main_BJ_2206_벽부수고이동하기2 {
 
    static class info {
        int x, y, dis, wall;
 
        public info(int x, int y, int dis, int wall) {
            this.x = x;
            this.y = y;
            this.dis = dis;
            this.wall = wall;
        }
    }
 
    static int N, M,K, ans = Integer.MAX_VALUE;
    static int[][] map;
    static boolean[][][] visited;
    static int[] dx = { -1010 };
    static int[] dy = { 010-1 };
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        K = Integer.parseInt(st.nextToken());
 
        map = new int[N][M];
        visited = new boolean[N][M][K+1];
 
        for (int i = 0; i < N; i++) {
            String str = br.readLine();
            for (int j = 0; j <M; j++) {
                map[i][j] = str.charAt(j) - 48;
            }
        }
        move();
    }
 
    public static void move() {
        Queue<info> queue = new LinkedList<>();
 
        queue.offer(new info(0010));
 
        visited[0][0][0= true;
 
        while (!queue.isEmpty()) {
            info temp = queue.poll();
 
            if (temp.x == N-1 && temp.y == M-1) {
                System.out.println(temp.dis);
                return ;
            }
 
            for (int i = 0; i < 4; i++) {
                int nx = temp.x + dx[i];
                int ny = temp.y + dy[i];
                int breakWall = temp.wall;
                int count = temp.dis;
 
                if (range(nx, ny)) {
                    if (map[nx][ny] == 1) { //벽일때
                        if(breakWall <&& !visited[nx][ny][breakWall+1]) {
                            visited[nx][ny][breakWall+1= true;
                            queue.offer(new info(nx, ny, count+1, breakWall+1));
                        }
                    } 
                    else {
                        if (!visited[nx][ny][breakWall]) {
                            visited[nx][ny][breakWall] = true;
                            queue.offer(new info(nx, ny, count + 1 ,breakWall));
                        }
                    }
                }
            }
        }
        System.out.println(-1);
    }
 
    public static boolean range(int x, int y) {
        return x >= 0 && y >= 0 && x < N && y < M;
    }
 
}
cs

 

풀이 방법

왼쪽 상단에서 오른쪽 하단의 위치까지 이동하는데 만약 이동하는 도중 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 K개 까지 부수고 이동하는데 최단 경로를 구하는 문제였습니다.

 

벽을 몇 개 부수고 이동했는지 확인하기 위해 3차원 배열을 이용했습니다. 먼저, 처음 위치인 (0, 0) 좌표 값과 이동한 거리, 그리고 벽을 부순 개수의 정보를 큐에 넣어주었습니다. 상하좌우로 이동하면서 만약 다음 이동할 위치가 벽이고, 현재까지 부슨 벽의 개수가 K보다 적고 방문하지 않은 곳이라면 해당 위치에 방문했다고 표시해주고 큐에 해당 정보를 넣어주었습니다. 그 외에 다음 이동할 위치가 길이라면 이동할 수 있으므로 방문했다고 표시해주고 큐에 해당 정보를 넣어주었습니다. 이 과정을 반복하다가 만약 오른쪽 아래에 도착했다면 도착하는데 걸린 거리를 출력해주었습니다. 만약 오른쪽 하단의 위치까지 이동할 수 없다면 -1을 출력해주었습니다.

 

문제

로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오.

로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 벽 또는 빈 칸이다. 청소기는 바라보는 방향이 있으며, 이 방향은 동, 서, 남, 북중 하나이다. 지도의 각 칸은 (r, c)로 나타낼 수 있고, r은 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로 부터 떨어진 칸의 개수이다.

로봇 청소기는 다음과 같이 작동한다.

  1. 현재 위치를 청소한다.
  2. 현재 위치에서 현재 방향을 기준으로 왼쪽방향부터 차례대로 탐색을 진행한다.
    1. 왼쪽 방향에 아직 청소하지 않은 공간이 존재한다면, 그 방향으로 회전한 다음 한 칸을 전진하고 1번부터 진행한다.
    2. 왼쪽 방향에 청소할 공간이 없다면, 그 방향으로 회전하고 2번으로 돌아간다.
    3. 네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을 하고 2번으로 돌아간다.
    4. 네 방향 모두 청소가 이미 되어있거나 벽이면서, 뒤쪽 방향이 벽이라 후진도 할 수 없는 경우에는 작동을 멈춘다.

로봇 청소기는 이미 청소되어있는 칸을 또 청소하지 않으며, 벽을 통과할 수 없다.

 

입력

첫째 줄에 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 50)

둘째 줄에 로봇 청소기가 있는 칸의 좌표 (r, c)와 바라보는 방향 d가 주어진다. d가 0인 경우에는 북쪽을, 1인 경우에는 동쪽을, 2인 경우에는 남쪽을, 3인 경우에는 서쪽을 바라보고 있는 것이다.

셋째 줄부터 N개의 줄에 장소의 상태가 북쪽부터 남쪽 순서대로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 빈 칸은 0, 벽은 1로 주어진다. 지도의 첫 행, 마지막 행, 첫 열, 마지막 열에 있는 모든 칸은 벽이다.

로봇 청소기가 있는 칸의 상태는 항상 빈 칸이다.

 

출력

로봇 청소기가 청소하는 칸의 개수를 출력한다.

 

예제

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main_BJ_14503_로봇청소기 {
    
    static int N,M,r,c,d, ans;
    static int [][] map;
    static int [] dx = {-1,0,1,0};
    static int [] dy = {0,1,0,-1};
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        st = new StringTokenizer(br.readLine());
 
        N = Integer.parseInt(st.nextToken());
        M= Integer.parseInt(st.nextToken());
        
        map = new int [N][M];
        
        st = new StringTokenizer(br.readLine());
        
        r = Integer.parseInt(st.nextToken());
        c = Integer.parseInt(st.nextToken());
        d = Integer.parseInt(st.nextToken());
        
        for(int i=0;i<N;i++) {
            st = new StringTokenizer(br.readLine());
            for(int j=0;j<M;j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        
        isClean(r,c,d);
        
        System.out.println(ans);
 
    }
    
    public static void isClean(int x, int y, int dir) {
        
        if(map[x][y]==0) {
            map[x][y]=2;
            ans++;
        }
        
        boolean flag = false;
        int direction = dir;
        
        for(int i=0;i<4;i++) {
            //북서남동으로 회전
            int nd = (dir+3)%4;
            int nx = x+dx[nd];
            int ny = y+dy[nd];
            if(range(nx,ny)) {
                if(map[nx][ny]==0) { // 왼쪽방향에 청소할 공간 존재
                    isClean(nx,ny,nd);
                    flag = true;
                    break;    
                } 
            }
            dir = nd;
        }
        
        //여기에 왔다면 c/d만 가능
        if(!flag) {
            // 처음 위치에서 뒤로 한칸
            int nd = (direction+2) %4;
            int nx = x+dx[nd];
            int ny = y+dy[nd];
            if(range(nx,ny) && map[nx][ny]!=1) {
                isClean(nx,ny,direction); //바라보는 방향 유지하면서 후진
            }
        }
    }
    
    public static boolean range(int x, int y) {
        return x>=0 && x<N && y>=0 && y<M;
    }
 
}
cs

 

풀이 방법

로봇 청소기가 청소하는 영역의 개수를 구하는 문제였습니다.

 

만약 해당 위치가 벽이 아니라면 청소할 수 있는 곳이므로 영역의 개수를 +해주었습니다. 해당 위치에서 왼쪽 방향에 청소할 영역이 존재한다면 그 방향으로 회전 및 한 칸 전진 후 1번부터 다시 진행하도록 해주었습니다. 반대로 왼쪽방향에 청소할 영역이 없다면 북서남동 방향으로 회전하면서 청소할 영역을 찾았습니다. isClean() 메소드에서 69번 줄에 왔다면 작동 조건 2-a, 2-b를 만족하지 않는다는 의미므로 2-c, 2-d 고려해볼 수 있습니다. 만약 해당 위치에서 뒤로 한칸 이동할 수 있는 경우에는 후진 후 다시 2번부터 진행하도록 해주고, 뒤로 한칸 이동할 수 없는 경우에는 작동을 멈춰 지금까지 청소한 영역의 개수를 출력해주었습니다.

문제

N개의 수로 이루어진 수열 A1, A2, ..., AN이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 N-1개의 연산자가 주어진다. 연산자는 덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷)으로만 이루어져 있다.

우리는 수와 수 사이에 연산자를 하나씩 넣어서, 수식을 하나 만들 수 있다. 이때, 주어진 수의 순서를 바꾸면 안 된다.

예를 들어, 6개의 수로 이루어진 수열이 1, 2, 3, 4, 5, 6이고, 주어진 연산자가 덧셈(+) 2개, 뺄셈(-) 1개, 곱셈(×) 1개, 나눗셈(÷) 1개인 경우에는 총 60가지의 식을 만들 수 있다. 예를 들어, 아래와 같은 식을 만들 수 있다.

  • 1+2+3-4×5÷6
  • 1÷2+3+4-5×6
  • 1+2÷3×4-5+6
  • 1÷2×3-4+5+6

식의 계산은 연산자 우선 순위를 무시하고 앞에서부터 진행해야 한다. 또, 나눗셈은 정수 나눗셈으로 몫만 취한다. 음수를 양수로 나눌 때는 C++14의 기준을 따른다. 즉, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다. 이에 따라서, 위의 식 4개의 결과를 계산해보면 아래와 같다.

  • 1+2+3-4×5÷6 = 1
  • 1÷2+3+4-5×6 = 12
  • 1+2÷3×4-5+6 = 5
  • 1÷2×3-4+5+6 = 7

N개의 수와 N-1개의 연산자가 주어졌을 때, 만들 수 있는 식의 결과가 최대인 것과 최소인 것을 구하는 프로그램을 작성하시오.

 

입력

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

 

출력

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

 

예제

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main_BJ_14888_연산자끼워넣기 {
    
    static int N, max = Integer.MIN_VALUE, min = Integer.MAX_VALUE;
    static int [] number, sign, cal;
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        
        
        N = Integer.parseInt(br.readLine());
        
        number = new int[N];
        sign = new int[4];
        cal = new int[N];
        
        st = new StringTokenizer(br.readLine());
        for(int i=0;i<N;i++) {
            number[i] = Integer.parseInt(st.nextToken());
        }
        
        st = new StringTokenizer(br.readLine());
        for(int i=0;i<4;i++) {
            sign[i] = Integer.parseInt(st.nextToken());
        }
        
        backtracking(1);
        System.out.println(max);
        System.out.println(min);
 
    }
    
    public static void backtracking(int cnt) {
        if(cnt ==N) {
            
            int result = number[0];
            
            for(int i=1;i<N;i++) {
                if(cal[i]==0) {
                    result = result+number[i];
                }else if(cal[i]==1) {
                    result = result-number[i];
                }else if(cal[i]==2) {
                    result = result*number[i];
                }else if(cal[i]==3) {
                    result = result/number[i];
                }
            }
            
            max = Math.max(result, max);
            min = Math.min(result, min);
            
            return;
        }
        
        for(int i=0;i<4;i++) {
            if(sign[i]>0) {
                cal[cnt] = i;
                sign[i]--;
                backtracking(cnt+1);
                sign[i]++;
            }
        }
        
    }
}
cs

 

풀이 방법

N개의 수와 N-1개의 연산자가 주어졌을 때, 만들 수 있는 식의 결과의 최대/최소를 구하는 문제였습니다.

 

N개의 수를 담을 number배열과 연산자의 개수를 담을 sign배열, 그리고 계산할 연산자를 담을 cal배열을 사용했습니다.

backtracking() 메서드에서 sign배열의 길이만큼 for문을 통해 만약 연산자가 존재한다면 cal배열에 연산자 값을 넣어주고 해당 sign값을 -1 해주었습니다. N-1개의 연산자를 cal배열에 다 넣어줬을 경우, number배열과 cal배열에 들어있는 연산자를 이용해 결괏값을 계산해주었습니다. 

 

문제

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다.

N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 N이 주어진다. (1 ≤ N < 15)

 

출력

첫째 줄에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 출력한다.

 

예제

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main_BJ_9663_NQueen {
    
    static int N, ans;
    static int [] map;
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        N = Integer.parseInt(br.readLine());
        
        map = new int[N];
        
        backtracking(0);
        System.out.println(ans);
    }
    
    public static void backtracking(int cnt) {
        if(cnt ==N) {
            ans++;
            return;
        }
        
        for(int i=0;i<N;i++) {
            map[cnt] =i;
            if(isCheck(cnt)) {
                backtracking(cnt+1);
            }
        }
    }
    
    public static boolean isCheck(int x) {
        for(int i=0;i<x;i++) {
            if(map[i]==map[x]) return false;
            else if(Math.abs(map[i]-map[x])==Math.abs(i-x)) return false;
        }
        return true;
    }
 
}
cs

 

+ Recent posts