반응형

문제 링크: www.acmicpc.net/problem/4256

 

4256번: 트리

문제 이진 트리는 매우 중요한 기본 자료 구조이다. 아래 그림은 루트 노드가 유일한 이진 트리이다. 모든 노드는 최대 2개의 자식 노드를 가질 수 있으며, 왼쪽 자식이 순서가 먼저이다. 노드 n��

www.acmicpc.net

<문제 풀이> DFS(깊이 우선 탐색), 트리

전위 순회 결과 3 6 5 4 8 7 1 2 

중위 순회 결과 5 6 8 4 3 1 2 7

중위 순회 결과를 통해서 각 노드의 순서를 알 수 있고, 왼쪽 서브 트리와 오른쪽 서브 트리에 어떤 노드가 존재하는지 알 수 있습니다.

그리고 전위 순회 결과를 통해 규칙을 찾아볼 수 있는데, 크기가 n인 배열에 전위 순회 결과가 차례로 저장돼 있다고 했을 때 인덱스 + 1을 하면 왼쪽 서브 트리의 루트를 가리키게 할 수 있습니다.

예를 들어 arr [] = {3 ,6, 5, 4, 8, 7, 1, 2]인 배열이 있습니다. 이때

root == 3, index = 0 되고, 왼쪽 서브 트리로 이동하면

root == 6, index = 1 이 됩니다.

 

그리고 오른쪽 서브트리로 이동하는 방법은 왼쪽 서브 트리의 크기 + 1 만큼 인덱스를 더해주면 됩니다.

 

root == 3, index = 0

root == 7, index = 0 + 4 + 1 == 5

 

 

 

<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
#include <iostream>
#include <vector>
using namespace std;
 
int preorder[1001];
int inorder[1001];
 
 
void solution(int root, int s, int e){
    for(int i = s ; i < e; i++){
        if(inorder[i] == preorder[root]){
            solution(root + 1, s, i); // left sub tree
            solution(root + i + 1 - s, i + 1, e); // right sub tree
            cout<<preorder[root]<<" ";
        }
    }
}
 
int main(void) {
    int test_case; 
    cin>>test_case;
    while(test_case--){
        int n ; cin>>n;
        for(int i=0; i<n; i++){
            cin >> preorder[i];
        }
        for(int i=0; i<n; i++){
            cin >> inorder[i];
        }
        solution(00, n);
        cout<<'\n';
    }
    return 0;
}
cs

 

 

 

반응형
반응형

문제 링크: https://www.acmicpc.net/problem/10974

 

10974번: 모든 순열

N이 주어졌을 때, 1부터 N까지의 수로 이루어진 순열을 사전순으로 출력하는 프로그램을 작성하시오.

www.acmicpc.net

<문제 풀이> 순열

백트래킹을 생각하면 쉽게 모든 순열을 구할 수 있다.

 

<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
#include <iostream>
#include <vector>
using namespace std;
 
#define MAX 8
bool visited[MAX + 1];
vector<int> elements;
int n;
void permutaiotn(){
    if(elements.size() == n){
        for(auto e : elements){
            cout<<e<<" ";
        }
        cout<<"\n";
    }else{
        for(int i=1; i<=n; i++){
            if(visited[i])continue;
            visited[i] = true;
            elements.push_back(i);
            permutaiotn();
            visited[i] = false;
            elements.pop_back();
        }
    }
 
}
 
int main(void) {
    cin >> n;
    permutaiotn();
    return 0;
}
cs
반응형
반응형

문제 링크: https://www.acmicpc.net/problem/2623

 

2623번: 음악프로그램

첫째 줄에는 가수의 수 N과 보조 PD의 수 M이 주어진다. 가수는 번호 1, 2,…,N 으로 표시한다. 둘째 줄부터 각 보조 PD가 정한 순서들이 한 줄에 하나씩 나온다. 각 줄의 맨 앞에는 보조 PD가 담당한 가수의 수가 나오고, 그 뒤로는 그 가수들의 순서가 나온다. N은 1이상 1,000이하의 정수이고, M은 1이상 100이하의 정수이다.

www.acmicpc.net

<문제 풀이> 위상 정렬

 

위상 정렬 알고리즘을 그대로 구현하면 되는데, 입력받은 순서를 그래프로 표현했을 때 사이클이 존재하면 0을 출력해합니다.

 

위상 정렬했을 때 결과 리스트의 크기가 정점의 개수 n과 다르면 사이클이 존재합니다.

 

<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
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
 
int n, m;
vector<int> adj[1001];
vector<int> res;
int indegree[1001];
void solve() {
    queue<int> q;
    for (int i = 1; i <= n; i++if (!indegree[i]) q.push(i);
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        res.push_back(cur);
        for (auto& next : adj[cur]) {
            indegree[next]--;
            if (!indegree[next]) q.push(next);
            
        }
    }
    if (res.size() != n) { //사이클이 존재하면
        res.clear();
        res.push_back(0);
    }
}
 
int main(void) {
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
 
    cin >> n >> m;
 
    while (m--) {
        int num;
        cin >> num;
        int prev;
        cin >> prev;
        num--;
        while (num--) {
            int cur;
            cin >> cur;
            adj[prev].push_back(cur);
            indegree[cur]++;
            prev = cur;
        }
    }
    solve();
    for (auto& e : res) cout << e << '\n';
 
    return 0;
}
cs

 

반응형
반응형

문제 링크: https://www.acmicpc.net/problem/2252

 

2252번: 줄 세우기

첫째 줄에 N(1≤N≤32,000), M(1≤M≤100,000)이 주어진다. M은 키를 비교한 회수이다. 다음 M개의 줄에는 키를 비교한 두 학생의 번호 A, B가 주어진다. 이는 학생 A가 학생 B의 앞에 서야 한다는 의미이다. 학생들의 번호는 1번부터 N번이다.

www.acmicpc.net

<문제 풀이> 그래프, 위상 정렬

위상 정렬 알고리즘을 그대로 적용하면 되는 문제입니다.

 

1. indegree가 0인 정점을 모두 큐에 넣는다.

2. 큐가 빌 때까지 다음을 반복한다.

3. 큐에서 정점을 하나 꺼낸다.

4. 꺼낸 정점을 결과 리스트에 넣고 정점의 인접 리스트를 확인한다.

5. 꺼낸 정점과 연결된 다른 정점의 indegree을 1 감소시킨다.

5. 만약 연결된 정점의 indegree를 1 감소시켰을 때 indegree가 0이 되면 그 정점을 큐에 넣는다. 

 

<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
44
45
46
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
 
int indegree[32001];
vector<int> adj[32001];
vector<int> res;
int n, m;
 
void solve() {
    queue<int> q;
    for (int i = 1; i <= n; i++if (!indegree[i]) q.push(i);
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        res.push_back(cur);
        for (auto& next : adj[cur]) {
            indegree[next]--;
            if (!indegree[next])q.push(next);
        }
    }
    
}
 
int main(void) {
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
 
    cin >> n >> m;
 
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b;
        adj[a].push_back(b);
        indegree[b]++;
    }
    solve();
 
    for (auto& e : res) {
        cout << e << " ";
    }
 
 
    return 0;
}
cs
 

 

반응형
반응형

문제 링크: https://www.acmicpc.net/problem/2250

 

2250번: 트리의 높이와 너비

첫째 줄에 노드의 개수를 나타내는 정수 N(1 ≤ N ≤ 10,000)이 주어진다. 다음 N개의 줄에는 각 줄마다 노드 번호와 해당 노드의 왼쪽 자식 노드와 오른쪽 자식 노드의 번호가 순서대로 주어진다. 노드들의 번호는 1부터 N까지이며, 자식이 없는 경우에는 자식 노드의 번호에 -1이 주어진다.

www.acmicpc.net

<문제 풀이> 트리

트리의 루트를 기준으로 왼쪽 서브 트리, 오른쪽 서브 트리를 각각 중위 순회하면 노드들의 열 번호를 알 수 있습니다.


왼쪽 서브트리를 중위 순회한 결과는 (8, 4, 2, 14, 9, 18, 15, 5, 10)
오른쪽 서브트리를 중위 순회한 결과는 (16, 11, 6, 12, 3, 17, 19, 13, 7)


그러면 벡터에 다음을 4가지를 push 하면 인덱스로 트리에서 각 정점의 열 번호를 알 수 있습니다.

 

1. 인덱스를 1부터 사용하기위해 0 push

2. 루트의 왼쪽 서브트리 중위 순회 결과 push

3. 루트 push

4. 루트의 오른쪽 서브트리 중위 순회 결과 push

 

vector = (0, 8, 4, 2, 14, 9, 18, 15, 5, 10, 1, 16, 11, 6, 12, 3, 17, 19, 13, 7)

 

그리고 이제 bfs로 레벨 순회를 해서 각 정점의 레벨을 알아낸 뒤 레벨별로 너비의 최댓값을 구하면 됩니다.

 

<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
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
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
 
int n;
int lc[10001];
int rc[10001];
int level[10001];
bool isRoot[10001];
vector<int> col;
 
 
int getRoot() {
    for (int i = 1; i <= n; i++) {
        if (lc[i] != -1) isRoot[lc[i]] = false;
        if (rc[i] != -1) isRoot[rc[i]] = false;
    }
    for (int i = 1; i <= n; i++if (isRoot[i]) return i;
}
 
/*레벨 순회*/
void bfs(int root) {
    queue<int> q;
    q.push(root);
    level[root] = 1;
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        if (lc[cur] != -1) {
            q.push(lc[cur]);
            level[lc[cur]] = level[cur] + 1;
        };
        if (rc[cur] != -1) {
            q.push(rc[cur]);
            level[rc[cur]] = level[cur] + 1;
        }
    }
}
 
/*중위 순회*/
void inorder(int root) {
    if (lc[root] != -1) inorder(lc[root]);
    col.push_back(root);
    if (rc[root] != -1)inorder(rc[root]);
}
 
int main(void) {
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
 
    cin >> n;
 
    fill(lc, lc + 10001-1);
    fill(rc, rc + 10001-1);
 
    for (int i = 0; i < n; i++) {
        int v, l, r;
        cin >> v >> l >> r;
        lc[v] = l;
        rc[v] = r;
        isRoot[v] = true//처음엔 모든 정점을 root로 가정
    }
 
 
    int root = getRoot();
    bfs(root); // 레벨 순회
    col.push_back(0); // 열 인덱스를 1부터 사용하기 위함
    if (lc[root] != -1) inorder(lc[root]); // 루트의 왼쪽 노드 col 벡터에 추가
    col.push_back(root); // root 노드 col 벡터에 추가
    if (rc[root] != -1) inorder(rc[root]); // 루트의 오른쪽 노드 col 백터에 추가
 
    int size = col.size();
    int width = 0;
    int min_level = 10000;
 
    for (int s = 1; s < size; s++) {
        for (int e = size - 1; e >= s; e--) {
            if (level[col[s]] == level[col[e]]) {
                if (e - s + 1 == width) {
                    width = e - s + 1;
                    min_level = min(min_level, level[col[s]]);
                }
                else if (e - s + 1 > width) {
                    min_level = level[col[s]];
                    width = e - s + 1;
                }
                break;
            }
        }
    }
 
    cout << min_level << " " << width;
    return 0;
}
cs

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 2623번] 음악프로그램  (0) 2020.04.11
[백준 2252번] 줄 세우기  (0) 2020.04.03
[백준 11725번] 트리의 부모 찾기  (0) 2020.03.26
[백준 1043번] 거짓말  (0) 2020.03.25
[백준 6118번] 숨바꼭질  (0) 2020.03.23
반응형

문제 링크: https://www.acmicpc.net/problem/11725

 

11725번: 트리의 부모 찾기

루트 없는 트리가 주어진다. 이때, 트리의 루트를 1이라고 정했을 때, 각 노드의 부모를 구하는 프로그램을 작성하시오.

www.acmicpc.net

<문제 풀이> 그래프, 트리, DFS, BFS

 

트리는 그래프의 특수한 형태이므로 그래프 탐색을 그대로 사용하면 됩니다. 노드 1을 시작으로 bfs를 돌리면 되는데, 각 노드의 인접한 노드들을 큐에 넣을 때는 부모를 제외한 자식 노드들만 넣으면 됩니다. 왜냐하면 큐에서 꺼낸 각 노드의 부모는 이전에 이미 방문했기 때문입니다. 

<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
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
 
vector<int>adj[100001];
int parents[100001];
int n;
 
void bfs() {
    queue<int> q;
    q.push(1);
    while (!q.empty()) {
        int cur = q.front();
        q.pop();
        for (auto& next : adj[cur]) {
            if (parents[cur] == next)continue;
            q.push(next);
            parents[next] = cur;
        }
    }
}
 
int main(void) {
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
    
    cin >> n;
    
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
 
    bfs();
 
    for (int i = 2; i <= n; i++) {
        cout << parents[i] << '\n';
    }
 
    return 0;
}
cs

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 2252번] 줄 세우기  (0) 2020.04.03
[백준 2250번] 트리의 높이와 너비  (0) 2020.03.30
[백준 1043번] 거짓말  (0) 2020.03.25
[백준 6118번] 숨바꼭질  (0) 2020.03.23
[백준 5567번] 결혼식  (0) 2020.03.22
반응형
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <windows.h>
using namespace std;
 
 
/*커서 숨기기(0) or 보이기(1) */
void CursorView(char show) {
    HANDLE hConsole;
    CONSOLE_CURSOR_INFO ConsoleCursor;
 
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
 
    ConsoleCursor.bVisible = show;
    ConsoleCursor.dwSize = 1;
 
    SetConsoleCursorInfo(hConsole, &ConsoleCursor);
}
 
 
int main(void) {
    //CursorView(true); // 커서 보이기
    CursorView(false); // 커서 숨기기
    return 0;
}
cs

include <windows.h>

반응형
반응형
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <windows.h>
using namespace std;
 
/*콘솔 커서 위치 이동*/
void gotoxy(int x, int y) {
    COORD pos = { x,y };
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
 
int main(void) {
    gotoxy(63); // x좌표가 y좌표보다 크기가 2배 정도 작다.
    cout << ". -> (6,3)";
    return 0;
}
cs

include <windows.h>

void gotoxy(int x, int y) {

    COORD pos = { x,y };

    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);

}

 

→ x축

↓ y 축

x좌표가 y좌표보다 크기가 2배 정도 작다.

호출 ex) gotoxy(6, 3);

반응형

+ Recent posts