기술 블로그

1267번 작업순서 본문

알고리즘 문제/SW Expert Academy

1267번 작업순서

parkit 2018. 8. 25. 11:15
728x90
반응형

이 글의 모든 문제와 사진, 자료 등은 SW Expert Academy에 있음을 말씀드립니다.





문제 : https://www.swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV18TrIqIwUCFAZN


풀이 : https://www.swexpertacademy.com/main/learn/course/lectureVideoPlayer.do






처음에 아무런 생각없이 단순히 DFS로 방문한 정점부터 출력하는 줄 알았는데 그게 아니었다.


예를 들어, 아래와 같은 노드들이 있다고 하자.



우리가 원하는 답은


8, 9, 4, 1, 5, 2, 3, 7, 6 이거나 4, 1, 2, 3, 8, 5, 7, 6, 9 이다.


4, 1, 2, 3, 8, 5, 7, 6, 9을 보면 출력 순서빨간 색으로 표시했다.



잘 보면, 자식이 없는 노드에서 부모 노드로 거슬러 올라가(파란 색) 출력 순서를 그 부모 노드부터 하고 있음을 알 수 있다.





따라서, 의사 코드는 아래와 같다.


1
2
3
4
5
6
7
8
9
DFS(현재 노드)
{
    while (부모 노드가 없어질 때 까지)
    {
        DFS(부모 노드);
    }
 
    현재 노드 처리(printf)
}
cs




하지만, 예외가 발생할 수 있음을 알 수 있는데, 예를 들어


노드(정점)가 3개 있는데, 1의 오른쪽 자식을 3, 1의 왼쪽 자식을 2라고 하자.


2와 3은 서로 관계가 없다.


이럴 때, DFS(2)가 DFS(1)을 호출하고, DFS(3)이 DFS(1)을 호출하므로, 방문 여부를 통해 중복을 방지해야 한다.





1. [DFS] 4, 1, 2, 3, 8, 5, 7, 6, 9 순서로 출력하는 코드(leaf 노드부터 부모 노드로 올라가는 방식)

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
#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <math.h>
#include <algorithm>
 
using namespace std;
 
bool visit[1001= { false, };
 
int child[1001= { 0, };
int info[1001][1001= { 0, };
// info[a][b] : 자식 노드인 a의 부모 수가 b 그리고 그 값 자체가 순서대로 부모
int parent_count[1001= { 0, }; // 부모 수
 
void DFS(int node)
{
    if (visit[node]) return;
 
    visit[node] = true;
 
    for (int i = 0; i < parent_count[node]; i++// node의 부모 수 만큼 실행
    {
        DFS(info[node][i]); // 그 node의 부모를 DFS로 실행
    }
 
    printf("%d ", node); 
    // 끝까지 올라갔다가, 그 정상부터 아래로 출력(부모 → 자식)
}
 
int main(void)
{
    for (int tc = 1; tc <= 10; tc++)
    {
        int V = 0, E = 0, p = 0, c = 0;
 
        memset(visit, falsesizeof(visit));
        memset(child, 0sizeof(child));
        memset(info, 0sizeof(info));
        memset(parent_count, 0sizeof(parent_count));
 
        scanf("%d %d"&V, &E);
 
        for (int i = 0; i < E; i++)
        {
            scanf("%d %d"&p, &c);
            // p → c 이므로 p가 부모, c는 자식
 
            child[p]++;
            // p의 자식 수를 검사
            // child[p]가 0이면 p는 leaf 노드이다.(자식 수가 0이므로)
 
            info[c][parent_count[c]++= p;
            // 자식 기준으로 부모를 추가
            // info[자식 노드][그 자식 노드의 부모 수를 센다. 실행될 수록 1씩 증가] = 그 부모
            // parent_count[c]의 값은 c의 부모 수
        }
 
        printf("#%d ", tc);
 
        for (int i = 1; i <= V; i++)
        {
            if (child[i] == 0 && !visit[i]) // 자식이 없고 방문하지 않았다면
            {
                DFS(i);
            }
        }
    }
 
    return 0;
}
cs








2. [DFS] 8, 9, 4, 1, 5, 2, 3, 7, 6 순서로 출력하는 코드 (루트 노드부터 leaf 노드로 내려가는 방식)

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
#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <math.h>
#include <algorithm>
 
using namespace std;
 
bool visit[1001= { false, };
 
int child[1001= { 0, };
int info[1001][1001= { 0, };
int Stack[1001= { 0, };
int Top;
int parent[1001= { 0, };
 
void DFS(int node)
{
    if (visit[node]) return;
 
    visit[node] = true;
 
    for (int i = 0; i < child[node]; i++// node의 자식 수 만큼 실행
    {
        DFS(info[node][i]); // 그 node의 자식을 DFS 실행
    }
 
    Stack[Top++= node;
    // 맨 처음에 맨 아래 leaf 노드부터 삽입이 되므로,
    // 출력할 때는 역순으로 출력해야한다. Top - 1 ~ 0
}
 
int main(void)
{
    for (int tc = 1; tc <= 10; tc++)
    {
        int V = 0, E = 0, p = 0, c = 0;
 
        memset(visit, falsesizeof(visit));
        memset(child, 0sizeof(child));
        memset(info, 0sizeof(info));
        memset(Stack, 0sizeof(Stack));
        memset(parent, 0sizeof(parent));
 
        scanf("%d %d"&V, &E);
 
        for (int i = 0; i < E; i++)
        {
            scanf("%d %d"&p, &c);
            // p → c 이므로 p가 부모, c는 자식
 
            info[p][child[p]++= c;
            parent[c]++
            // c의 부모 수 조사
            // child[p]는 p의 자식 수
        }    
 
        Top = 0;
 
        for (int i = 1; i <= V; i++)
        {
            if (parent[i] == 0 && !visit[i]) // 부모가 없고, 방문하지 않았다면
            {
                DFS(i);
            }
        }
 
        printf("#%d ", tc);
 
        for (int i = Top - 1; i >= 0; i--)
        {
            printf("%d ", Stack[i]);
        }
    }
 
    return 0;
}
cs






3. [BFS] 부모 모드가 없는 경우'만' queue에 push 한다.
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
#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <math.h>
#include <algorithm>
 
using namespace std;
 
bool visit[1001= { false, };
 
int child[1001= { 0, };
int info[1001][1001= { 0, };
int Stack[1001= { 0, };
int parent[1001= { 0, };
 
queue<int> q;
 
int main(void)
{
    for (int tc = 1; tc <= 10; tc++)
    {
        int V = 0, E = 0, p = 0, c = 0;
 
        memset(visit, falsesizeof(visit));
        memset(child, 0sizeof(child));
        memset(info, 0sizeof(info));
        memset(Stack, 0sizeof(Stack));
        memset(parent, 0sizeof(parent));
 
        scanf("%d %d"&V, &E);
 
        for (int i = 0; i < E; i++)
        {
            scanf("%d %d"&p, &c);
            // p → c 이므로 p가 부모, c는 자식
 
            info[p][child[p]++= c;
 
            parent[c]++
            // c의 부모 수 조사
        }    
 
        for (int i = 1; i <= V; i++)
        {
            if(parent[i] == 0) q.push(i);
        }
 
        printf("#%d ", tc);
 
        while (!q.empty())
        {
            int qSize = q.size();
 
            while (qSize--)
            {
                int here = q.front();
 
                q.pop();
 
                if (visit[here]) continue;
 
                visit[here] = true;
 
                printf("%d ", here);
 
                for (int i = 0; i < child[here]; i++)
                {
                    int ch = info[here][i];
 
                    parent[ch]--;
 
                    if(parent[ch] == 0) q.push(ch);
                    // 부모가 없는 경우에만 push
                }
            }
        }
    }
 
    return 0;
}
cs






위의 풀이DFS와 BFS 구현 방식 및 각 단계 별로 그림을 설명해주신다. 

시간이 날 때 마다 꼭 보자.


728x90
반응형

'알고리즘 문제 > SW Expert Academy' 카테고리의 다른 글

2382번 미생물 격리  (0) 2018.08.29
1952번 수영장  (0) 2018.08.27
1953번 탈주범 검거  (0) 2018.08.25
2383번 점심 식사시간  (0) 2018.08.25
4013번 특이한 자석  (0) 2018.08.24