반응형

https://www.acmicpc.net/problem/20947

 

20947번: 습격받은 도시

$N$개의 줄에 도시의 정보를 출력한다. 각 줄은 $N$개의 문자를 포함하며 $i$번째 줄 $j$번째 문자는 도시의 세로 $i$번째 가로 $j$번째 칸에 대한 정보이다. 빈칸일 경우 ., 건물일 경우 O, 건물 잔해

www.acmicpc.net

접근법


1. 모든 .를 탐색하여 폭탄을 놓을 수 있는 곳에 놓기 

 

=> 시간 초과

=> 모든 점 탐색(4,000,000) * 점 하나당 가로, 세로 검사(2,000 + 2,000)

=> 4,000,000*4,000

=> 16,000,000,000 (제한시간 3초)

 

2. 모든 .를 탐색하여 일단 폭탄을 다 놓고, O를 탐색하여 놓을 수 없는 위치의 폭탄 제거

 

=> 틀렸습니다

=> 잔해가 없는 곳에는 폭탄을 설치하면 안됨

 

3

...

...

...

 

3. 모든 X를 탐색하여 폭탄을 놓을 수 있는 위치에 놓고

   모든 O를 탐색하여 놓을 수 없는 위치의 폭탄 제거

 

=> 맞았습니다!!

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>
#define rep(i,n) for(int i=0;i<n;i++)
using namespace std;
int n;
char arr[2001][2001];
void input();
void print();
void findX();
void findO();
void addBomb(int x, int y) {
    // 우측
    int i = y + 1;
    while (arr[x][i] == '.')
        arr[x][i++= 'B';
    // 좌측
    i = y - 1;
    while (arr[x][i] == '.')
        arr[x][i--= 'B';
    // 위쪽
    i = x - 1;
    while (arr[i][y] == '.')
        arr[i--][y] = 'B';
    // 아래쪽
    i = x + 1;
    while (arr[i][y] == '.')
        arr[i++][y] = 'B';
}
void removeBomb(int x, int y) {
    // 우측
    int i = y + 1;
    while (arr[x][i] == 'B'|| arr[x][i] == '.')
        arr[x][i++= '.';
    // 좌측
    i = y - 1;
    while (arr[x][i] == 'B'|| arr[x][i] == '.')
        arr[x][i--= '.';
    // 위쪽
    i = x - 1;
    while (arr[i][y] == 'B'|| arr[i][y] == '.')
        arr[i--][y] = '.';
    // 아래쪽
    i = x + 1;
    while (arr[i][y] == 'B'|| arr[i][y] == '.')
        arr[i++][y] = '.';
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    input();
    findX();
    findO();
    print();
}
void input(){
    cin >> n;
    rep(i, n) {
        rep(j, n)
            cin >> arr[i][j];
    }
}
void print(){
    rep(i, n) {
        rep(j, n)
            cout << arr[i][j];
        cout << '\n';
    }
}
void findX(){
    rep(i, n) {
        rep(j, n) {
            if (arr[i][j] == 'X')
                addBomb(i, j);
        }
    }
}
void findO(){
    rep(i, n) {
        rep(j, n) {
            if (arr[i][j] == 'O')
                removeBomb(i, j);
        }
    }
}
cs

 

반응형

'백준 > 구현' 카테고리의 다른 글

백준 16926  (0) 2021.02.21
반응형

https://www.acmicpc.net/problem/17837

 

17837번: 새로운 게임 2

재현이는 주변을 살펴보던 중 체스판과 말을 이용해서 새로운 게임을 만들기로 했다. 새로운 게임은 크기가 N×N인 체스판에서 진행되고, 사용하는 말의 개수는 K개이다. 말은 원판모양이고, 하

www.acmicpc.net

https://youtu.be/fAs85oVcu1g

접근법은 위 동영상과 동일하다.

말의 위치를 나타내는 node_map[][]

말의 정보를 나타내는 node_arr[]를 사용했다.

하지만 구현을 잘 못해서 그런지, 4%에서 틀렸습니다가 계속 떴다

테스트 케이스 5개는 모두 맞게 나오고 질문 게시판도 다 읽어봤는데 원인을 못 찾았다...

 

5번 테스트 케이스의 진행과정


01234567

진행과정은 백준 게시판에 있는 설명과 동일하다

https://www.acmicpc.net/board/view/49492

 

글 읽기 - test 케이스별 참고자료

댓글을 작성하려면 로그인해야 합니다.

www.acmicpc.net

질문 게시판에서 4%에서 틀렸습니다가 뜬다는 글을 읽어보면 배열 범위 문제인 것 같은데,

배열 범위도 넉넉하게 잡았고, 범위 체크도 다 한 것 같은데...

 

파란색 혹은 벽을 만났을 때 반대 방향으로 이동 시, 반대 방향의 색 (흰 / 빨강 / 파랑)도 체크했고,

빨간색 칸에 기존 말이 존재할 경우, 기존 말의 순서는 바뀌지 않고 새로 이동한 말의 순서만 뒤집는 것도 체크했다.

 

소스코드 (4%에서 틀렸습니다.)


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
#include <iostream>
#include <vector>
#include <stack>
#define rep(i,n) for(int i=1;i<=n;i++)
using namespace std;
struct Node {
    int i, j, d, idx;
};
int dx[] = { -100-11 };
int dy[] = { -11-100 };
int n, k;
int arr[13][13];
vector<int> node_map[13][13];
Node node_arr[11];
stack<int> s;
void input();
void changeDirection(Node &now) {
    if (now.d == 1) now.d = 2;
    else if (now.d == 2) now.d = 1;
    else if (now.d == 3) now.d = 4;
    else if (now.d == 4) now.d = 3;
}
int func() {
    int cnt = 1;
    while (cnt <= 1000) {
        rep(i, k) {
            // 지금 이동시킬 말이 몇 번째 칸에서 몇 번째 순서인지 확인하기
            Node start = node_arr[i];
            int x = start.i;
            int y = start.j;
 
            // 현재 말 위에 쌓여있는 것들은 현재 말의 방향 따라 움직임
            int nx = x + dx[start.d];
            int ny = y + dy[start.d];
 
            bool added = true;
            // 현재 말의 위치에서 현재 말보다 뒤에 (위에) 있는 것들은 다 같이 이동시키기
        
            for (int idx = start.idx; idx < node_map[x][y].size(); idx++) {
                int node_num = node_map[x][y][idx];
                Node &now = node_arr[node_num];
 
                // 다음 칸이 벽 또는 파란색
                if (nx<1 || nx>|| ny<1 || ny>|| arr[nx][ny] == 2) {
                    changeDirection(now);
                    
                    nx = now.i + dx[now.d];
                    ny = now.j + dy[now.d];
                    
                    // 이동할 칸이 파란색이면 정지
                    if (nx<1 || nx>|| ny<1 || ny>|| arr[nx][ny] == 2) {
                        added = false;
                        break;
                    }
                }
                // 위치 이동
                now.i = nx;
                now.j = ny;
                
                // 다음 칸이 흰 색
                if (arr[nx][ny] == 0) {
                    now.idx = node_map[nx][ny].size();
                    node_map[nx][ny].push_back(node_num);
                }
 
                // 다음 칸이 빨간 색
                else if (arr[nx][ny] == 1) {
                    // 순서 뒤집어야함
                    s.push(node_num);
                }
 
                // 이동시킨 칸에 말이 4개 쌓이면 즉시 종료
                if (node_map[nx][ny].size() >= 4)
                    return cnt;
            }
 
            // 빨간색일 경우 처리
            while (!s.empty()) {
                int now = s.top(); s.pop();
                node_arr[now].idx = node_map[nx][ny].size();
                node_map[nx][ny].push_back(now);
            }
 
            // 기존 칸에서 지우기
            while (added&&node_map[x][y].size() > start.idx)
                node_map[x][y].erase(node_map[x][y].begin() + start.idx);
        }
        cnt++;
    }
    return cnt;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    input();
    int ret = func();
    cout << (ret > 1000 ? -1 : ret);
}
void input() {
    cin >> n >> k;
    rep(i, n) {
        rep(j, n)
            cin >> arr[i][j];
    }
    rep(i, k) {
        Node node;
        cin >> node.i >> node.j >> node.d;
        node.idx = 0;
        node_arr[i] = node;
        node_map[node.i][node.j].push_back(i);
    }
}
cs
반응형

'백준 > 삼성기출' 카테고리의 다른 글

백준 17779 [복습 필수]  (0) 2021.08.06
백준 17142  (0) 2021.08.04
백준 17143  (0) 2021.07.19
백준 5373 [복습필수]  (0) 2021.04.30
백준 16234  (0) 2021.04.30
반응형

https://www.acmicpc.net/problem/17779

 

17779번: 게리맨더링 2

재현시의 시장 구재현은 지난 몇 년간 게리맨더링을 통해서 자신의 당에게 유리하게 선거구를 획정했다. 견제할 권력이 없어진 구재현은 권력을 매우 부당하게 행사했고, 심지어는 시의 이름

www.acmicpc.net

처음 접근법


: 5구역을 먼저 계산하고 1~4구역을 계산

 

① 5구역 계산하면서 visited 체크

② 1~4구역을 문제에서 주어진 수식대로 범위를 지정하여 계산.

    for문을 돌리면서 visited 처리가 된 것은 5구역에 포함되는 부분이므로, 각 구역 계산 시 포함시키지 않음

 

문제점

1~4구역 나누는 것은 문제에 주어진 수식을 참고하여 코드를 작성했지만,

5구역 나누는 법은 도무지 생각이 나지 않았다...

 

두 번째 접근법 (블로그 참고)


: 1~4구역을 먼저 계산하고 5구역을 계산

 

① 1~4구역 계산 시, if 문에서 5구역을 걸러내는 조건을 이용해서 5구역 필터링.

② 전체 영억 - (1~4구역) 으로 5구역 계산

 

문제점

5구역을 걸러내는 조건이 아주 까다로웠다...

그림을 그려봐도, 코드를 계속 읽어봐도 이해가 안됐다.

무엇보다 비슷한 유형의 문제를 풀 때, 이 방법대로 구현할 자신이 없었다.

 

세 번째 접근법 (유튜브 참고): https://youtu.be/fAs85oVcu1g


 

 

: 5구역의 경계를 설정하고, 1~4구역 계산 시 필터링

 

 

① 문제에서 주어진 5구역 경계 수식을 참고하여 5구역 경계 설정

② 1~4구역 계산 시 5구역의 경계를 만나면 다음 행으로 넘어감

 

해결

이 영상 보자마자 바로 방법을 깨달았다.

단순하게 5구역의 경계만 설정함으로써 간단하게 1~4구역을 계산할 수 있었다.

복잡하게 5구역을 먼저 계산할 필요도, 1~4구역 계산 시 5구역 필터링을 어렵게 할 필요도 없는 것이다.

5구역의 경계를 설정하는 수식은 아주 간단하다. 문제에 있는 조건을 그대로 이용하면 된다.

 

문제에서 주어진 5구역의 경계

5구역의 경계를 표시하는 소스코드

1
2
3
4
5
6
7
8
9
    // 5구역 경계 설정
    for (int i = 0; i <= d1; i++) {
        border[x + i][y - i] = 5;             // 5-1 경계 (x, y), (x+1, y-1), ..., (x+d1, y-d1)
        border[x + d2 + i][y + d2 - i] = 5;   // 5-4 경계 (x+d2, y+d2), (x+d2+1, y+d2-1), ..., (x+d2+d1, y+d2-d1)
    }
    for (int i = 0; i <= d2; i++) {
        border[x + i][y + i] = 5;             // 5-2 경계 (x, y), (x+1, y+1), ..., (x+d2, y+d2)
        border[x + d1 + i][y - d1 + i] = 5// 5-3 경계 (x+d1, y-d1), (x+d1+1, y-d1+1), ... (x+d1+d2, y-d1+d2)
    }
cs

 

1~4구역 계산도 마찬가지로 문제에 주어진 수식을 활용하여 쉽게 수행할 수 있다.

 

문제에서 주어진 1~4구역의 범위

1~4구역 계산하는 소스코드

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
    // 1번 선거구: 1 ≤ r < x+d1, 1 ≤ c ≤ y
    for (int i = 1; i < x+d1; i++) {
        for (int j = 1; j <= y; j++) {
            if (border[i][j] == 5break;
            area[1+= arr[i][j];
        }
    }
    // 2번 선거구 : 1 ≤ r ≤ x + d2, y < c ≤ N
    for (int i = 1; i <= x + d2; i++) {
        for (int j = n; j > y; j--) {
            if (border[i][j] == 5break;
            area[2+= arr[i][j];
        }
    }
    // 3번 선거구 : x + d1 ≤ r ≤ N, 1 ≤ c < y - d1 + d2
    for (int i = x+d1; i <= n; i++) {
        for (int j = 1; j < y-d1+d2; j++) {
            if (border[i][j] == 5break;
            area[3+= arr[i][j];
        }
    }
    // 4번 선거구 : x + d2 < r ≤ N, y - d1 + d2 ≤ c ≤ N
    for (int i = x + d2+1; i <= n; i++) {
        for (int j = n; j >= y-d1+d2; j--) {
            if (border[i][j] == 5break;
            area[4+= arr[i][j];
        }
    }
    // 5번 선거구
    area[5= total;
    rep(i, 4)
        area[5-= area[i];
cs

 

진행 과정

0123

전체 소스코드

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
#include <iostream>
#include <algorithm>
#include <cstring>
#define rep(i,n) for(int i=1;i<=n;i++)
using namespace std;
int n, arr[21][21], area[6], border[21][21];
int max_val, min_val, ans = 1e9, total;
void input();
void init();
bool isValidArea(int x, int y, int d1, int d2);    // 범위 검사
void getArea(int x, int y, int d1, int d2);        // 범위 계산
 
// 1. (x, y), d1, d2 정하기
// 2. 구역 별 인구수 계산
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    input();
 
    for (int x = 1; x <= n;x++) {
        for (int y = 1; y <= n;y++) {
            for (int d1 = 1; d1 < n; d1++) {
                for (int d2 = 1;d2 < n;d2++) {
                    init();
                    if (isValidArea(x, y, d1, d2)) {
                        getArea(x, y, d1, d2);
                        ans = min(ans, max_val - min_val);
                    }
                }
            }
        }
    }
    cout << ans;
}
bool isValidArea(int x, int y, int d1, int d2) {
    if (x<1 || x>|| y<1 || y>n) return 0;    //    상: (x,y)
    if (x + d1 + d2<1 || x + d1 + d2>|| y - d1 + d2<1 || y - d1 + d2>n) return 0;    //    하: (x+d1+d2, y-d1+d2)
    if (x + d1<1 || x + d1>|| y - d1<1 || y - d1>n) return 0;    //    좌: (x+d1, y-d1)
    if (x + d2<1 || x + d2>|| y + d2<1 || y + d2>n) return 0;    //    우: (x+d2, y+d2)
    return 1;
}
// 범위 계산
void getArea(int x, int y, int d1, int d2) {
    // 5구역 경계 설정
    for (int i = 0; i <= d1; i++) {
        border[x + i][y - i] = 5;            // 5-1 경계 (x, y), (x+1, y-1), ..., (x+d1, y-d1)
        border[x + d2 + i][y + d2 - i] = 5;    // 5-4 경계 (x+d2, y+d2), (x+d2+1, y+d2-1), ..., (x+d2+d1, y+d2-d1)
    }
    for (int i = 0; i <= d2; i++) {
        border[x + i][y + i] = 5;            // 5-2 경계 (x, y), (x+1, y+1), ..., (x+d2, y+d2)
        border[x + d1 + i][y - d1 + i] = 5// 5-3 경계 (x+d1, y-d1), (x+d1+1, y-d1+1), ... (x+d1+d2, y-d1+d2)
    }
 
    // 1번 선거구: 1 ≤ r < x+d1, 1 ≤ c ≤ y
    for (int i = 1; i < x+d1; i++) {
        for (int j = 1; j <= y; j++) {
            if (border[i][j] == 5break;
            area[1+= arr[i][j];
        }
    }
    // 2번 선거구 : 1 ≤ r ≤ x + d2, y < c ≤ N
    for (int i = 1; i <= x + d2; i++) {
        for (int j = n; j > y; j--) {
            if (border[i][j] == 5break;
            area[2+= arr[i][j];
        }
    }
    // 3번 선거구 : x + d1 ≤ r ≤ N, 1 ≤ c < y - d1 + d2
    for (int i = x+d1; i <= n; i++) {
        for (int j = 1; j < y-d1+d2; j++) {
            if (border[i][j] == 5break;
            area[3+= arr[i][j];
        }
    }
    // 4번 선거구 : x + d2 < r ≤ N, y - d1 + d2 ≤ c ≤ N
    for (int i = x + d2+1; i <= n; i++) {
        for (int j = n; j >= y-d1+d2; j--) {
            if (border[i][j] == 5break;
            area[4+= arr[i][j];
        }
    }
    // 5번 선거구
    area[5= total;
    rep(i, 4)
        area[5-= area[i];
 
    rep(i, 5) {
        max_val = max(max_val, area[i]);
        min_val = min(min_val, area[i]);
    }
}
 
void input() {
    cin >> n;
    rep(i, n) {
        rep(j, n) {
            cin >> arr[i][j];
            total += arr[i][j];
        }
    }
}
void init() {
    memset(area, 0sizeof(area));
    memset(border, 0sizeof(border));
    max_val = -1;
    min_val = 1e9;
}
cs
반응형

'백준 > 삼성기출' 카테고리의 다른 글

백준 17837 [4%에서 틀렸습니다.]  (0) 2021.08.08
백준 17142  (0) 2021.08.04
백준 17143  (0) 2021.07.19
백준 5373 [복습필수]  (0) 2021.04.30
백준 16234  (0) 2021.04.30
반응형

https://www.acmicpc.net/problem/17142

 

17142번: 연구소 3

인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고

www.acmicpc.net

1. 백트래킹으로 활성화 할 바이러스 선택

  - 2차원 배열에서 백트래킹하면 시간초과

  - arr[i][j] = 2인 {i, j} 값을 벡터에 저장시킨 뒤, 해당 벡터에 대해서 백트래킹 수행

 

2. m개 활성시켰으면 BFS로 시간 계산

  - arr[i][j]에서 BFS 수행하면 입력이 변경되므로, 다음 백트래킹 수행 시 계산 잘못됨

  - arr[i][j]가 아니라 copy_arr[i][j]에서 BFS 수행

 

0: 빈 칸

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
#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
#include <vector>
#define rep(i,n) for(int i=0;i<n;i++)
#define pii pair<intint>
using namespace std;
queue<pii> q;
vector<pii> virus;
int n, m, arr[51][51], copy_arr[51][51], zero_cnt, ans = 1e9;
bool visited[51][51];
int dx[] = { -1010 };
int dy[] = { 010-1 };
void input();
void bfsInit() {
    memset(visited, 0sizeof(visited));
    while (!q.empty())
        q.pop();
    zero_cnt = 0;
    rep(i, n) {
        rep(j, n) {
            copy_arr[i][j] = arr[i][j];
            // 활성화된 바이러스를 queue에 삽입하고 방문처리
            if (copy_arr[i][j] == 3) {
                q.push({ i,j });
                visited[i][j] = 1;
            }
            // 빈 칸의 개수 체크
            else if (copy_arr[i][j] == 0) zero_cnt++;
        }
    }
}
// return 시간(초)
int bfs() {
    int cnt = 0;
    bfsInit();
    while (!q.empty()) {
        int size = q.size();
        // 빈 칸 없으면 종료
        if (zero_cnt == 0break;
        while (size--) {
            pii now = q.front(); q.pop();
            int x = now.first;
            int y = now.second;
            visited[x][y] = 1;
            rep(i, 4) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                if (nx < 0 || nx >= n || ny < 0 || ny >= n || visited[nx][ny]) continue;
                // 1: 벽이라서 멈춤
                if (copy_arr[nx][ny] == 1continue;
 
                // 0, 2: 활성화 상태(3)로 변경 후 전파시킴
                else if (copy_arr[nx][ny] == 0 || copy_arr[nx][ny]==2) {
                    if (copy_arr[nx][ny] == 0) zero_cnt--;
                    copy_arr[nx][ny] = 3;
                    visited[nx][ny] = 1;
                    q.push({ nx, ny });
                }
                
                // 3: 이미 visited라서 걸러질 것
            }
        }
        cnt++;
    }
    return cnt;
}
 
void backTrackking(int idx, int cnt) {
    // 바이러스를 m개 만큼 활성화 시켰으면 bfs 실행
    if (cnt == m) {
        int ret = bfs();
 
        // 빈 칸 개수가 0개일 때만 갱신
        if (zero_cnt == 0)
            ans = min(ans, ret);
        return;
    }
 
    // 백트래킹으로 활성화시킬 바이러스 찾기
    for (int i = idx; i < virus.size(); i++) {
        int x = virus[i].first;
        int y = virus[i].second;
        if (arr[x][y] == 2) {
            arr[x][y] = 3;
            backTrackking(i, cnt + 1);
            arr[x][y] = 2;
        }
    }
}
// 1. 활성화 시킬 바이러스 선택하기 (백트래킹)
// 2. 시간 얼마나 걸리는지 계산하기 (bfs)
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    input();
    backTrackking(00);
    cout << (ans==1e9?-1:ans);
}
 
void input() {
    cin >> n >> m;
    rep(i, n) {
        rep(j, n) {
            cin >> arr[i][j];
            if (arr[i][j] == 2)
                virus.push_back({ i,j });
        }
    }
}
cs

 

반응형

'백준 > 삼성기출' 카테고리의 다른 글

백준 17837 [4%에서 틀렸습니다.]  (0) 2021.08.08
백준 17779 [복습 필수]  (0) 2021.08.06
백준 17143  (0) 2021.07.19
백준 5373 [복습필수]  (0) 2021.04.30
백준 16234  (0) 2021.04.30
반응형

https://www.acmicpc.net/problem/9470

 

9470번: Strahler 순서

지질학에서 하천계는 유향그래프로 나타낼 수 있다. 강은 간선으로 나타내며, 물이 흐르는 방향이 간선의 방향이 된다. 노드는 호수나 샘처럼 강이 시작하는 곳, 강이 합쳐지거나 나누어지는 곳

www.acmicpc.net

 

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
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#define rep(i,n) for(int i=1;i<=n;i++)
using namespace std;
vector<vector<int> > v;
queue<int> q;
struct Node {
    int val;    // 들어오는 순서 중 최댓값
    bool dup;    // val의 중복 여부
};
int in_degree[1001], order[1001];
Node temp[1001];
int t, k, m, p, a, b;
void input();
void findZeroIndegree();
void topologySort() {
    while (!q.empty()) {
        int now = q.front(); q.pop();
        for (int next : v[now]) {
            // 들어오는 값 중에서 최댓값 찾기
            // 1. 중복 (X)
            if (order[now] > temp[next].val) {
                temp[next].val = order[now];
                temp[next].dup = 0;
            }
            // 2. 중복 (O)
            else if (order[now] == temp[next].val) 
                temp[next].dup = 1;
            
            if (--in_degree[next] == 0) {
                // 들어오는 값 더 없으면 순서 갱신
                order[next] = temp[next].val + (temp[next].dup ? 1 : 0);
                q.push(next);
            }
        }
    }
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> t;
    while (t--) {
        input();
        findZeroIndegree();
        topologySort();
        cout << k << ' ' << order[m] << '\n';
    }
}
void input() {
    cin >> k >> m >> p;
    v.clear();
    v.resize(m + 1);
    memset(temp, 0sizeof(temp));
    memset(order, 0sizeof(order));
    memset(in_degree, 0sizeof(in_degree));
    rep(i, p) {
        cin >> a >> b;
        v[a].push_back(b);
        in_degree[b]++;
    }
}
void findZeroIndegree() {
    rep(i, m) {
        if (in_degree[i] == 0) {
            q.push(i);
            order[i] = 1;
        }
    }
}
cs
반응형

'백준' 카테고리의 다른 글

백준 1197  (0) 2021.07.12
백준 1922  (0) 2021.07.12
백준 2252  (0) 2021.07.12
반응형

https://www.acmicpc.net/problem/2213

 

2213번: 트리의 독립집합

첫째 줄에 트리의 정점의 수 n이 주어진다. n은 10,000이하인 양의 정수이다. 1부터 n사이의 정수가 트리의 정점이라고 가정한다. 둘째 줄에는 n개의 정수 w1, w2, ..., wn이 주어지는데, wi는 정점 i의

www.acmicpc.net

1. 최댓값 찾기

012345

2. 출력

01234

소스코드 

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
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#define rep(i,n) for(int i=1;i<=n;i++)
#define pii pair<intint>
 
using namespace std;
vector<vector<int> > v;
vector<pii> child[10001][2];
priority_queue<int> pq;
int n, dp[10001][2], a,b;
bool visited[10001];
void input();
void print();
void dfs(int now) {
    for (int next : v[now]) {
        if (!visited[next]) {
            visited[next] = 1;
            dfs(next);
 
            // now 미포함
            if (dp[next][0> dp[next][1]) {
                dp[now][0+= dp[next][0];
                child[now][0].push_back({ next,0 });
            }
            else {
                dp[now][0+= dp[next][1];
                child[now][0].push_back({ next,1 });
            }
 
            // now 포함
            dp[now][1+= dp[next][0];
            child[now][1].push_back({ next, 0 });
        }
    }
}
 
void trace(int now, int idx) {
    if (idx == 1)
        pq.push(-now);
    for (pii next : child[now][idx]) 
        trace(next.first, next.second);
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    input();
    visited[1= 1;
    dfs(1);
 
    if (dp[1][0> dp[1][1]) trace(10);
    else trace(11);
 
    print();
}
 
void input() {
    cin >> n;
    v.resize(n + 1);
    rep(i, n)
        cin >> dp[i][1];
    rep(i, n - 1) {
        cin >> a >> b;
        v[a].push_back(b);
        v[b].push_back(a);
    }
}
void print() {
    cout << max(dp[1][0], dp[1][1]) << '\n';
    while (!pq.empty()) {
        cout << -pq.top() << ' ';
        pq.pop();
    }
}
cs
반응형

'백준 > 트리DP' 카테고리의 다른 글

백준 2533 [복습필수]  (0) 2021.08.01
백준 15681  (0) 2021.07.30
백준 1005  (0) 2021.07.24
반응형

https://www.acmicpc.net/problem/2533

 

2533번: 사회망 서비스(SNS)

페이스북, 트위터, 카카오톡과 같은 사회망 서비스(SNS)가 널리 사용됨에 따라, 사회망을 통하여 사람들이 어떻게 새로운 아이디어를 받아들이게 되는가를 이해하는 문제가 중요해졌다. 사회망

www.acmicpc.net

DP

dp[i][0]: 본인이 얼리어답터가 아님 -> 이웃 모두 얼리어답터
dp[i][1]: 본인이 얼리어답터임        -> 이웃 얼리어답터 상관 없이 작은 값 

 

점화식

dp[now][0] += dp[next][1]

dp[now][1] += min(dp[next][0], dp[next][1])

 

간선 양방향 및 visited 쓰는 이유

간선 단방향으로 입력할 경우, 간선 a, b 순서가 바뀌면 값이 달라짐

8

1 2

1 3

1 4

2 5

2 6

4 7

4 8

 

8
2 1
3 1
4 1
5 2
6 2
7 4
8 4

진행과정

0123456

소스 코드

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
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define rep(i,n) for(int i=1;i<=n;i++)
using namespace std;
vector<vector<int> > v;
int n, a, b, visited[1000001];
int dp[1000001][2];    // dp[i][0]: 본인이 얼리어답터가 아님    -> 이웃 모두 얼리어답터
                    // dp[i][1]: 본인이 얼리어답터임        -> 얼리어답터 상관없음
void func(int now) {
    dp[now][1= 1;
    for (int next : v[now]) {
        if (!visited[next]) {
            visited[next] = 1;
            func(next);
            dp[now][0+= dp[next][1];
            dp[now][1+= min(dp[next][0], dp[next][1]);
        }
    }
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n;
    v.resize(n + 1);
    rep(i, n-1) {
        cin >> a >> b;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    visited[1= 1;
    func(1);
    cout << min(dp[1][0], dp[1][1]);
}
cs
반응형

'백준 > 트리DP' 카테고리의 다른 글

백준 2213  (0) 2021.08.02
백준 15681  (0) 2021.07.30
백준 1005  (0) 2021.07.24
반응형

https://www.acmicpc.net/problem/15681

 

15681번: 트리와 쿼리

트리의 정점의 수 N과 루트의 번호 R, 쿼리의 수 Q가 주어진다. (2 ≤ N ≤ 105, 1 ≤ R ≤ N, 1 ≤ Q ≤ 105) 이어 N-1줄에 걸쳐, U V의 형태로 트리에 속한 간선의 정보가 주어진다. (1 ≤ U, V ≤ N, U ≠ V)

www.acmicpc.net

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
#include <iostream>
#include <vector>
#define rep(i,n) for(int i=1;i<=n;i++)
using namespace std;
vector<vector<int> > v;
int n, r, q, a, b,x, child[100001], visited[100001];
void input();
void print();
int func(int r) {
    for (int next : v[r]) {
        if (!visited[next]) {
            visited[next] = 1;
            child[r]+=func(next);
        }
    }
    return child[r] + 1;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    input();
    func(r);
    print();
}
void input() {
    cin >> n >> r >> q;
    v.resize(n + 1);
    rep(i, n - 1) {
        cin >> a >> b;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    visited[r] = 1;
}
void print() {
    rep(i, q) {
        cin >> x;
        cout << child[x] + 1 << '\n';
    }
}
cs
반응형

'백준 > 트리DP' 카테고리의 다른 글

백준 2213  (0) 2021.08.02
백준 2533 [복습필수]  (0) 2021.08.01
백준 1005  (0) 2021.07.24

+ Recent posts