챌린지/구름톤 챌린지

구름톤 챌린지 4주 차 학습 일기 (Day16 ~ 18)

imname1am 2023. 9. 10. 23:58
반응형

🧩 문제 16. 연합


> 배운 점

• 그래프 탐색 ⇨ BFS

인접 행렬 활용

 

> 필요 변수 및 자료구조

- int[][] graph            인접 행렬

- boolean[] visited  / int[] visited    섬 방문 여부 확인 & 연합 여부 확인

- Queue<Integer>          BFS 수행용

 

> 느낀 점

- 연합 개수 = BFS 수행 횟수

- 나는 boolean[] visited로 풀었는데,

int[] visited로 해서 while문 안에 현재 방문한 노드를 연합 번호에 할당하는 코드인 visited[now] = cnt; 를 넣어서 풀 수도 있다!

 

> 헷갈렸던 점

- while문 안에 들어가는 if문에서 간선의 존재 여부를 확인할 때,

   graph[now][next]graph[next][now]양방향 모두 확인해줘야한다..!!

 

 

> 정답 코드

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
import java.io.*;
import java.util.*;
 
class Main {
    static int N, M, cnt;    
    static int[][] graph;     // 인접 행렬
    static boolean[] visited; // 섬 방문 여부 확인 & 연합 여부 확인
    
    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());
        
        graph = new int[N + 1][N + 1];
        
        while(M --> 0) {
            st = new StringTokenizer(br.readLine(), " ");
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            
            graph[a][b] = 1; // 단방향
        }
        
        visited = new boolean[N + 1];
        for(int i = 1 ; i <= N ; i++) {
            if(!visited[i]) {
                bfs(i);
                cnt++;
            }
        }
        
        System.out.println(cnt);
    }
    
    private static void bfs(int num) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(num);
        
        visited[num] = true;
        
        while(!queue.isEmpty()) {
            int now = queue.poll();
            
            for(int next = 1 ; next <= N ; next++) {
                if(graph[now][next] == 1 && graph[next][now] == 1 && !visited[next]) {
                    queue.add(next);
                    visited[next] = true;
                }
            }            
        }
    }
}
cs

 

 

 

🧩 문제 17. 통신망 분석


> 배운 점

컴포넌트 : 그래프 내에서 서로 연결된 정점들의 집합

 

> 필요 변수 · 자료구조

Com(List<Integer> list, double val)   객체 (찾아낸 컴포넌트 리스트, 밀도)

 List<Integer> result                            정답 저장 리스트

Set<Integer> component                    도달한 컴퓨터들을 오름차순 집합으로 저장할 집합

 

> 느낀 점

  클래스에 List도 인자로 가질 수 있다!

  함수 리턴형을 객체로 받을 수도 있다!

  필요한 변수/자료구조가 어떤 것이 있는지 초장에 고민을 진득하게 하는 시간이 필요한 것 같다.

 

 

> 헷갈렸던 점

  도달한 컴퓨터들을 저장할 목록을 만들자

 

 

> 풀이

🔍 찾아야 할 것

1. 컴포넌트에 속한 컴퓨터 수

2. 컴포넌트에 속한 통신 회선 수

3. 컴포넌트에서 가장 작은 컴퓨터 번호

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
import java.util.*;
import java.io.*;
 
class Com {
    List<Integer> list; // 찾아낸 컴포넌트
    double val;         // 밀도
    
    public Com(List<Integer> list, double val) {
        this.list = list;
        this.val = val;
    }
}
 
public class Main {
    static int N, M;
 
    static List<Integer>[] A;
    static boolean[] visited;
    
    static List<Integer> result;    // 🔔 정답 저장 리스트
    static double density = 0;
    
    static StringBuilder sb = new StringBuilder();
    
    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());
        
        A = new ArrayList[N + 1];
        for(int i = 1 ; i <= N ; i++) {
            A[i] = new ArrayList<>();
        }
        visited = new boolean[N + 1];
        
        while(M --> 0) {
            st = new StringTokenizer(br.readLine(), " ");
            
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            
            A[a].add(b);
            A[b].add(a);
        }
        
        result = new ArrayList<>(); // 정답 저장 리스트
        
        for(int i = 1 ; i <= N ; i++) {
            if(!visited[i]) {
                Com com = bfs(i);
                
                List<Integer> tmp = com.list;
                double tmpDensity = com.val;
                
                if(Math.abs(tmpDensity - density) < 1e-8) { // [밀도가 같은 경우]
                    if(result.size() > tmp.size()) {        // 2번 조건) 현재 컴포넌트 배열이 더 크면, 컴퓨터 수가 가장 작은 컴포넌트 출력 (=result 값 확인)
                        result = tmp;
                        density = tmpDensity;
                    }
                    else if(result.size() == tmp.size()) {  // 3번 조건) 배열 크기가 같으면, 더 작은 컴퓨터 번호 갖는 컴포넌트 출력 (=첫 번째 값 비교)
                        if(tmp.get(0< result.get(0)) {
                            result = tmp;
                            density = tmpDensity;
                        }
                    }
                }
                else if(tmpDensity > density) { // [밀도가 다른 경우, 가장 밀도가 높은 컴포넌트 출력]
                    result = tmp;
                    density = tmpDensity;
                }
            }
        }
        
        for(int r : result) {
            sb.append(r).append(" ");
        }
        System.out.println(sb);
    }
    
    private static Com bfs(int num) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(num);
        
        Set<Integer> component = new TreeSet<>();   // 📍 도달한 컴퓨터들을 오름차순 집합으로 저장 (TreeSet : 객체 오름차순 정렬)
        
        while(!queue.isEmpty()) {
            int now = queue.poll();
            
            if(visited[now]) {
                continue;
            }
            
            visited[now] = true;
            component.add(now);
            
            for(int next : A[now]) {
                if(!visited[next]) {
                    queue.add(next);
                }
            }
        }
        
        /*** 🔔 내부 통선 회신 개수 확인 ***/
        int edge = 0;   // 간선 수 저장
        
        // 컴포넌트에 속한 모든 컴퓨터에 대해 순회
        for(int i : component) {
            for(int to : A[i]) {
                if(component.contains(to)) {    // contains 활용하기 위해 Set 쓰는 것!
                    edge++;
                }
            }
        }
        
        List<Integer> sortedList = new ArrayList<>(component);
        //Collections.sort(sortedList);
        
        return new Com(sortedList, (double) edge / component.size()); // "가장 밀도가 높은 컴포넌트" : 컴포넌트에 포함된 통신 회선 개수 / 컴퓨터 수
    }
}
cs

 

 

🧩 문제 18. 중첩 점


> 배운 점

DP - 3차원 매트릭스!

 

 

> 필요 변수 및 자료구조

 long[][][] dp = new int[2][][];         선 긋기를 중첩 기록해 모두 관리할 수 있는 DP 변수

  └ dp[0]  ⇨ 한 좌표에서 세로 선 개수만 기록

  └ dp[1]  ⇨ 한 좌표에서 가로 선 개수만  기록

 

• long spotCnt : 중첩 점 개수

 

[선 개수, 방향]을 갖고 있는 데이터 (객체/배열)가 필요하다!

 

• D / U (상하) : 가로 선을 관리하는 dp[1]에서 추출하며, dp[1]의 값을 갱신한다.

• R / L (좌우)  : 세로 선을 관리하는 dp[0]에서 추출하며, dp[0]의 값을 갱신한다.

 

 

> 느낀 점

3차원 매트릭스 dp배열. 며칠 전에 문제로 풀 때 이 생각을 우째하지 싶었는데 이 문제에서 또 사용되었다

 

여기서 상하좌우 방향을 만날 때마다 각자의 조건문에 맞춰 반복문을 매번 수행하고,

중첩 점 개수를 갱신하고, dp를 갱신해주면 되는 것이었다..

 

정답 코드 보니 그리 어렵지 않음,,,,ㅠ

 

반응형