<서론>

https://swexpertacademy.com/main/code/problem/problemDetail.do

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

www.swexpertacademy.com

코드는 결론에, 문제는 위 링크로

하루 2포스팅! 사실 포스팅 거리가 밀려서 바쁘게 글 올려야하는데, 귀찮아서 못올리고 있다. 일단 올리기 편한 알고리즘 문제들부터 빨리 해치워야지. 이 문제 역시 스터디를 위해 푼 문제고 제출순으로 했을 때 2번째로 많이 제출한 문제다(2019.04.24 D4 기준). 본론에서 말하겠지만 미리 말하자면 매우 단순한 완전 탐색 문제! 한 번 풀어보자.


 

 

<본론>

문제를 보자마자 '이거 dfs든 bfs든 6번 이동만 시키고 결과를 set에 넣으면 되겠다' 라는 생각이 들었다.

graph는 4*4로 고정이고 메서드마다 파라미터로 싣기 귀찮아서 static으로 선언했다.

가장자리 부분일 때 분기처리하기 귀찮아서, 1칸씩 여유를 줬고 가장자리에는 다 -1을 넣었다. 그래서 이동하고자 하는 칸이 -1이면 이동하지 않고 넘어가게 처리했다.

음... dfs로 풀었는데, 따로 설명할 건 없는 것 같다.

다만 이 문제를 처음 제출했을 때, 테스트케이스 하나만 맞고 틀렸다 나와서 약간 멘붕했었는데..

틀린 이유는 static으로 선언한 set을 각 테스트케이스마다 초기화해주지 않아서 일어난 일이었다.

이거때문에 알고리즘 문제인 줄 알고 한참을 고민했다.....


 

 

<결론>

1. 이중 포문을 이용해서 모든 점에서 move 메서드 호출

2. 이중 포문 끝나고 set의 사이즈 확인.

// move 메소드

1. 이동을 6번 했는지(depth==7) 확인

 1.1 이동을 6번 다했다면 지금까지 누적된 str을 set에 add

2. 현재 str에 현재 graph의 값을 더하기

3. 현재 점에서 동서남북 4방향으로 move 메소드 실행

 3.1 단, 다음 방향이 -1이 아닌 지점인 경우에만

 3.2 depth는 +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
import java.util.HashSet;
import java.util.Scanner;
 
public class Solution {
 
    static int[] dx = {0-101};
    static int[] dy = {10-10};
    static int[][] graph = new int[6][6];
    static HashSet<String> set = new HashSet<String>();
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int T= sc.nextInt();
        for(int test_case=1; test_case<=T; test_case++) {
            int ans = 0;
            for(int i=0; i<6; i++) {
                for(int j=0; j<6; j++) {
                    if(i!=0 && j!=0 && i!=5 && j!=5){
                        graph[i][j] = sc.nextInt();
                    } else graph[i][j] = -1;
                }
            }
            for(int i=1; i<=4; i++){
                for(int j=1; j<=4; j++){
                    move(0"", j,i);
                }
            }
            ans = set.size();
            System.out.println("#"+test_case+" "+ans);
            set.clear();
        }
        sc.close();
    }
    static void move(int depth, String str, int x, int y) {
        if(depth==7) {
            set.add(str);
            return;
        }
        str = str+""+graph[y][x];
        for(int i=0; i<4; i++) {
            if(graph[y+dy[i]][x+dx[i]]!=-1) {
                move(depth+1, str, x+dx[i], y+dy[i]);
            }
        }
    }
}
cs

<서론>

https://swexpertacademy.com/main/code/problem/problemDetail.do

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

www.swexpertacademy.com

정답 코드는 결론에..

위 링크는 문제 링크이다.

D4를 다 풀어보자! 라는 마인드로 D4문제를 풀고 있는데, 음.. 아직까지는 조금 쉬운 느낌이다. D5로 올려서 풀어야하나. 암튼 제출이 많은 순서대로 문제를 풀어보기로 했다! 그 중 첫번째가 바로 "3752 가능한 시험점수" 이다!


 

 

<본론>

처음 문제를 접했을 때, 이건 모든 경우를 다 구해서 set에 넣고 set의 사이즈를 구하면 되지 않을까 했다. 그리고 모든 경우를 combination 풀 듯 구해볼까 했다.

그런데..

만약 문제의 수가 최대 100개일때, 100 C 50은 어마어마한 경우의 수가 나오는 것이었다. 결국 다른 방법으로 풀어야겠다 생각하고 고민..

아무리 고민해봐도 이 문제는 모든 경우를 다 구해서 set에 넣는게 맞는 것 같았다. 그래서 모든 경우를 조금 다르게 구해보려 했다.

만약 N이 1이고 배점이 A라면

N=1 :0,  A

요렇게 2개가 나올 것이다. 근데 만약 여기서 B가 추가된다면?

N=2 : 0, A, B, A+B

이렇게 2개가 더해져 4개의 결과가 나왔다. C까지 추가된다면?

N=3 : 0, A, B, A+B, C, A+C, B+C, A+B+C

이렇게 4개가 더해져 8개가 되었다!

그렇다! 느낌 왔다! 문제가 x개 라면, x-1개 일때의 모든 경우의 수에 +x번째 수를 더한만큼 더 있으면 되는 것이었다!

중복값이 생겨도, set에 들어가면 중복이 제거되니 저런 식으로 구하고 set에 add만 해주면 되었다!

처음에 조금 생각을 했지만, 결국 금방 풀 수 있었다!


 

 

<결론>

SET은 중복을 허용하지 않는다.

N 경우의 수
N = 1 // A 0, A
N = 2 // A, B 0, A, 0+B, A+B
N = 3 // A, B, C 0, A, B, A+B, 0+C, A+C, B+C, A+B+C 
... ...

 

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.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
 
public class Solution {
 
    static Set<Integer> set = new HashSet<Integer>();
    
    public static void main(String[] args) {
 
        Scanner sc = new Scanner(System.in);
 
        int T = sc.nextInt();
        for (int test_case = 1; test_case <= T; test_case++) {
            set.clear();
            int ans = 0;
            int N = sc.nextInt();
            int[] qArray = new int[N];
            set.add(0);
            for (int i = 0; i < N; i++) {
                qArray[i] = sc.nextInt();
            }
            
            for(int i=0; i<qArray.length; i++) {
                scoreSelect(qArray[i]);
            }
            
            ans = set.size();
            System.out.println("#" + test_case + " " + ans);
        }
        sc.close();
    }
    
    static void scoreSelect(int num) {
        Set<Integer> tmpSet = new HashSet<Integer>(); 
        tmpSet.addAll(set);
        Iterator<Integer> it = tmpSet.iterator();
        while(it.hasNext()) {
            set.add(it.next()+num);
        }
    }
}
cs

<서론>

이번에 포스팅하는 알고리즘 문제는 최근 스터디를 진행하게 되면서 첫번째 과제로 하게 된 세 문제 중, 가장 난이도 낮은 문제다. SW Experts Academy에서 제공하는 문제 중 D4 난이도의 문제는 몽땅 다 풀어버려야지! 하는 마음 가짐으로 접근했는데, 생각보다 쉽지 않았다. 아무튼 각설하고 가장 쉽게 풀었던 7465번 문제를 본격적으로 포스팅하겠다.

 

참고로 문제 링크는..

https://www.swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWngfZVa9XwDFAQU&categoryId=AWngfZVa9XwDFAQU&categoryType=CODE

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

www.swexpertacademy.com

 


 

<본론>

첫번째와 마찬가지로 완성 코드는 결론에 놓겠다.

알고리즘 문제 풀이의 첫번째 글의 문제를 풀었을 때보다 2달이 지난 다음에 풀어서 그런지, DFS 문제는 손쉽게 풀 수 있게 된 것 같다(물론, 이번 문제가 특히 더 쉽다).  다른 방법으로 풀 수도 있겠지만 가장 빨리 생각난 방법으로 문제를 풀었다.

 

큰 틀은 이렇다.

이 문제는 서로 알고 지내는 무리가 몇 개인지 구하는 문제인데, 이는 결국 그래프의 개수를 구하는 문제라고 생각했다.

따라서,

1. 임의의 노드에서 DFS 방법으로 완전 탐색을 진행한다.

2. 완전 탐색이 다 끝난 후에도 아직 방문하지 노드가 있는 지 확인한다.

3. 만약 방문하지 않은 노드가 있다면, 이것은 다른 그래프가 또 존재한다는 뜻.

4. 다른 노드를 정해서 완전 탐색을 진행한다.

5. 1~4 반복

 

이것보다 더 최적의 방법이 있을 수도 있다고 생각하지만, 일단 내가 생각할 수 있는 선에서는 이것이 베스트였다. 사실 다른 방법은 생각도 못했지만...

같이 스터디를 진행하는 팀원은 이 문제를 Union find로 풀었다. 처음 들어보는 알고리즘이었다. Union find가 무엇인지 공부하고 그 방법으로도 풀어봐야겠다.

 


 

<결론>

요약

 1. N을 입력 받고, N*N 크기의 2차 배열(graph), N 크기의 배열(visited), 정답으로 쓸 ans(초기값 1) 생성

 2. 1번부터 시작해서 DFS 방법으로 완전 탐색

 3. 완전 탐색 후 visited 배열에 false값 있는지 확인

  3.1 false값이 있는 경우 ans++ 후 break

 4. ans 값 출력

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
import java.util.Scanner;
 
class Solution
{
    static int[][] graph;
    static boolean[] visited;
    public static void main(String args[])
    {
        Scanner sc = new Scanner(System.in);
        int T;
        T=sc.nextInt();
        for(int test_case = 1; test_case <= T; test_case++)
        {
            int n = sc.nextInt();
            int m = sc.nextInt();
            graph = new int[n+1][n+1];
            int ans = 1;
            visited = new boolean[n+1];
            for(int i=0; i<m; i++){
                int a = sc.nextInt();
                int b = sc.nextInt();
                graph[a][b] = 1;
                graph[b][a] = 1;
            }
            for(int i=1; i<n+1; i++){
                if(!visited[i]){
                    dfs(i, n+1);
                    for(int j=1; j<n+1; j++) {
                        if(!visited[j]) {
                            ans++;
                            break;
                        }
                    }
                }
            }
            System.out.println("#"+test_case+" "+ans);
        }
        sc.close();
    }
 
    static void dfs(int n, int tot) {
        if(!visited[n]) {
           visited[n] = true;
           for(int i=1; i<tot; i++){
               if(graph[n][i]==1 && !visited[i]) dfs(i, tot);
           }
        }
    }
}
cs

+ Recent posts