www.acmicpc.net/problem/2110

 

2110번: 공유기 설치

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가

www.acmicpc.net

M개의 공유기를 놓을 수 있는 최대한의 간격을 구하는 문제입니다.

최대한의 간격은 최적화된 정답을 구하는 것이므로 파라매트릭 서치로 해결합니다.

 

우선 이분탐색을 쓰기 위해 입력받은 위치정보를 정렬합니다.

탐색 범위는 간격이며, (1 ~ list[N] - list[1])의 범위에서 탐색합니다.

 

간격 m에서 공유기를 M개 이상 놓을 수 있는지 확인합니다.

놓을 수 있으면 true, 아니면 false를 리턴합니다.

 

solve함수의 리턴 값이 true면 ans에 현재 간격을 저장하고 (m + 1 ~ r) 범위를 탐색합니다.

solve함수의 리턴 값이 false면 (s ~ m - 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
46
47
48
49
50
51
52
53
#include <iostream>
#include <algorithm>
using namespace std;
 
int list[200001];
int N, M;
 
bool solve(int length) {
    int pre = list[1];
    int cnt = 1;
    for (int i = 2; i <= N; i++) {
        if (list[i] - pre >= length) {
            cnt++;
            pre = list[i];
        }
    }
 
    if (cnt >= M) return true;
    else return false;
}
 
int binarySearch(int l, int r) {
    int ans = 0;
 
    while (l <= r) {
        int m = (l + r) / 2;
        if (solve(m)) {
            ans = m;
            l = m + 1;
        }
        else r = m - 1;
    }
 
    return ans;
}
 
void input() {
    cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        cin >> list[i];
    }
    sort(list + 1, list + 1 + N);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    cout << binarySearch(1, list[N] - list[1]) << '\n';
 
    return 0;
}
cs

'algorithm > binarysearch' 카테고리의 다른 글

boj 18113 그르다 김가놈  (0) 2022.10.09
boj 2295 세 수의 합  (0) 2022.06.28
boj 7453 합이 0인 네 정수  (0) 2021.01.22
boj 2143 두 배열의 합  (0) 2021.01.22
boj 2805 나무 자르기  (0) 2021.01.22

www.acmicpc.net/problem/2458

 

2458번: 키 순서

1번부터 N번까지 번호가 붙여져 있는 학생들에 대하여 두 학생끼리 키를 비교한 결과의 일부가 주어져 있다. 단, N명의 학생들의 키는 모두 다르다고 가정한다. 예를 들어, 6명의 학생들에 대하여

www.acmicpc.net

 

처음에 이 그림을 보았을 때 위상정렬을 쓰는건가 하고 생각했었지만 순서 중 하나를 출력하는 것이 아닌 자신의 정확한 순서를 알고있는 학생의 수를 출력하는 문제였습니다.

 

저는 두 가지 방법으로 해결하였습니다.

먼저 dfs 방법입니다.

 

저는 2개의 벡터를 사용하였습니다. (자신보다 키가 큰 학생을 저장하는 벡터(f), 작은 학생을 저장하는 벡터(s))

한 학생을 시작으로 두번의 dfs를 수행합니다.

i번 학생보다 키가 큰 학생들을 dfs로 순회하고, 작은 학생들도 똑같이 dfs로 순회합니다.

순회하면서 next의 갯수만큼 cnt를 1씩 늘려줍니다.

 

두 번의 dfs가 끝나고 cnt가 N - 1이면 자신의 정확한 순서를 알 수 있습니다.

 

 

그 다음은 플로이드 방법입니다.

 

d[i][j] : i번 학생의 키 < j번 학생의 키 인 경우

 

플로이드로 자신보다 키가 큰 학생들을 모두 구합니다.

그 다음 i번 학생과 j번 학생의 관계를 확인합니다.

d[i][j] (i번이 j번보다 작은 경우) || d[j][i] (i번이 j번보다 큰 경우)

 

위의 조건을 만족한 횟수가 N - 1이면 자신의 정확한 순서를 알 수 있습니다.

 

dfs
플로이드

 

아무래도 플로이드가  N^3이라 dfs에 비해 속도가 느린 편입니다.

 

 

[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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
 
vector<int> f[501], s[501];
bool visit[501];
int N, M, cnt;
 
void dfs(vector<int> t[], int v) {
    visit[v] = true;
 
    for (int i = 0; i < t[v].size(); i++) {
        int next = t[v][i];
 
        if (visit[next]) continue;
 
        cnt++;
        dfs(t, next);
    }
}
 
void func() {
    int ans = 0;
    for (int i = 1; i <= N; i++) {
        memset(visit, falsesizeof(visit));
        dfs(f, i);
        memset(visit, falsesizeof(visit));
        dfs(s, i);
 
        if (cnt == N - 1) ans++;
        cnt = 0;
    }
 
    cout << ans << '\n';
}
 
void input() {
    int u, v;
    cin >> N >> M;
    while (M--) {
        cin >> u >> v;
        f[u].push_back(v);
        s[v].push_back(u);
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

 

 

[플로이드]

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>
#define INF 1000000000
using namespace std;
 
bool d[501][501];
int N, M, ans;
 
void solve() {
    for (int i = 1; i <= N; i++) {
        int cnt = 0;
        for (int j = 1; j <= N; j++) {
            if (d[i][j] || d[j][i]) cnt++;
        }
 
        if (cnt == N - 1) ans++;
    }
 
    cout << ans << '\n';
}
 
void func() {
    for (int k = 1; k <= N; k++) {
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                if (d[i][k] && d[k][j]) {
                    d[i][j] = true;
                }
            }
        }
    }
}
 
void input() {
    int u, v;
    cin >> N >> M;
    while (M--) {
        cin >> u >> v;
        d[u][v] = true;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
    solve();
 
 
    return 0;
}
cs

'algorithm > dfs' 카테고리의 다른 글

boj 19236 청소년 상어  (0) 2021.04.22
boj 2239 스도쿠  (0) 2021.04.16
boj 14889 스타트와 링크  (0) 2021.03.17
boj 2023 신기한 소수  (0) 2021.03.16
boj 14500 테트로미노  (0) 2021.03.15

www.acmicpc.net/problem/2564

 

2564번: 경비원

첫째 줄에 블록의 가로의 길이와 세로의 길이가 차례로 주어진다. 둘째 줄에 상점의 개수가 주어진다. 블록의 가로의 길이와 세로의 길이, 상점의 개수는 모두 100이하의 자연수이다. 이어 한 줄

www.acmicpc.net

시작점과 도착점 모두 가장자리에 있으며, 가장자리로만 인접한 좌표로 이동할 수 있습니다.

 

입력은 상점의 위치와 기준점에서의 거리가 주어집니다.

1 -> 북쪽

2 -> 남쪽

3 -> 서쪽

4 -> 동쪽

이렇게 위치하며

북쪽과 남쪽의 경우 왼쪽에서의 거리, 서쪽과 동쪽의 경우 위쪽에서의 거리를 나타냅니다.

 

10 5
3
1 4
3 2
2 8
2 3

즉 위의 케이스로는

(1, 4) : 북쪽이고, 왼쪽에서 4칸 떨어진 거리

(3, 2) : 서쪽이고, 위쪽에서 2칸 떨어진 거리

(2, 8) : 남쪽이고, 왼쪽에서 8칸 떨어진 거리

(2, 3) : 남쪽이고, 왼쪽에서 3칸 떨어진 거리

 

이제 모든 경우를 다 생각하여 계산해주시면 됩니다. (시작점 : (sp, sd), 도착점 : (ep, ed))

우선 시작점과 도착점의 위치(방향)이 같을 때(sp == ep)는 거리의 차이를 더합니다.

다음은 sp의 값에 따라 if문을 모두 추가하였습니다.

방향이 인접한 방향의 경우에는 각 상대방향 쪽으로 이동하는 것이 최소거리입니다.

방향이 인접한 방향이 아니라면 2방향으로 가는 경우 모두를 계산하여 최솟값을 구해주시면 됩니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static int list[][] = new int[101][2];
    static int N, M, K, sp, sd, ans;
 
    static void func() {
        for (int i = 0; i < K; i++) {
            int ep = list[i][0];
            int ed = list[i][1];
 
            if (sp == ep)
                ans += Math.abs(sd - ed);
            else if (sp == 1) {
                if (ep == 2) {
                    ans += Math.min(M + sd + ed, M + N - sd + N - ed);
                } else if (ep == 3) {
                    ans += (sd + ed);
                } else {
                    ans += (N - sd + ed);
                }
            } else if (sp == 2) {
                if (ep == 1) {
                    ans += Math.min(M + sd + ed, M + N - sd + N - ed);
                } else if (ep == 3) {
                    ans += (sd + M - ed);
                } else {
                    ans += (N - sd + M - ed);
                }
            } else if (sp == 3) {
                if (ep == 1) {
                    ans += (sd + ed);
                } else if (ep == 2) {
                    ans += (M - sd + ed);
                } else {
                    ans += (Math.min(N + sd + ed, N + M - sd + M - ed));
                }
            } else {
                if (ep == 1) {
                    ans += (sd + N - ed);
                } else if (ep == 2) {
                    ans += (M - sd + N - ed);
                } else {
                    ans += (Math.min(N + sd + ed, N + M - sd + M - ed));
                }
            }
        }
        
        System.out.println(ans);
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
 
        st = new StringTokenizer(br.readLine());
        K = Integer.parseInt(st.nextToken());
 
        for (int i = 0; i < K; i++) {
            st = new StringTokenizer(br.readLine());
            list[i][0= Integer.parseInt(st.nextToken());
            list[i][1= Integer.parseInt(st.nextToken());
        }
 
        st = new StringTokenizer(br.readLine());
        sp = Integer.parseInt(st.nextToken());
        sd = Integer.parseInt(st.nextToken());
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

'algorithm > Implementation' 카테고리의 다른 글

boj 20207 달력  (0) 2021.04.22
boj 17144 미세먼지 안녕!  (0) 2021.04.14
boj 16719 ZOAC  (0) 2021.03.15
boj 3085 사탕 게임  (0) 2021.02.26
boj 8320 직사각형을 만드는 방법  (0) 2021.02.25

www.acmicpc.net/problem/10800

 

10800번: 컬러볼

첫 줄에는 공의 개수를 나타내는 자연수 N이 주어진다(1 ≤ N ≤ 200,000). 다음 N개의 줄 중 i번째 줄에는 i번째 공의 색을 나타내는 자연수 Ci와 그 크기를 나타내는 자연수 Si가 주어진다(1 ≤ Ci ≤ N

www.acmicpc.net

 

어떤 공은 자신보다 색이 같거나 크기가 크거나 같은 공을 잡을 수 없습니다.

즉, 색이 다르고, 크기가 작은 공을 잡을 수 있습니다.

 

저는 공의 색에 대한 누적합(colorsum), 크기에 대한 누적합(sizesum), 전체 누적합(sum)을 모두 구하면서 답을 찾았습니다.

 

우선 공의 크기 -> 색 별로 오름차순 정렬합니다. (출력할 때 인덱스를 맞춰줘야하니 인덱스를 유지해줍니다.)

이제 크기가 작은 공부터 하나씩 꺼내 sum, colorsum, sizesum을 갱신합니다.

 

그럼 현재 공이 잡을 수 있는 공은

전체 합 - 같은 색의 크기 합 - 같은 크기의 크기 합 + 자신의 크기로 구해주시면 됩니다.

(같은 색과 같은 크기는 잡을 수 없으며 자신은 두 번 뺀 값이기때문에 자신의 크기를 더한 것입니다.)

 

하지만 이걸로 끝내기엔 예외가 하나 더 있습니다.

"자신과 색과 크기 모두 같은 공" 끼리는 답이 모두 같습니다.

저는 여기에서 예외처리가 안되어 pre배열에 이전 공의 정보를 유지하였습니다.

이전 공의 색과 크기가 모두 같으면 이전 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
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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.StringTokenizer;
 
public class Main {
    static class Pair {
        int idx;
        int color;
        int size;
 
        public Pair(int idx, int color, int size) {
            this.idx = idx;
            this.color = color;
            this.size = size;
        }
    }
 
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static ArrayList<Pair> list;
    static int sum[] = new int[200001];
    static int colorsum[] = new int[200001];
    static int sizesum[] = new int[2001];
    static int ans[] = new int[200001];
    static int N;
 
    static void func() {
        int pre[] = new int[3];
        for (int i = 1; i <= N; i++) {
            int idx = list.get(i - 1).idx;
            int color = list.get(i - 1).color;
            int size = list.get(i - 1).size;
 
            sum[i] = sum[i - 1+ size;
            colorsum[color] += size;
            sizesum[size] += size;
 
            if (color == pre[1&& size == pre[2])
                ans[idx] = ans[pre[0]];
            else
                ans[idx] = sum[i] - colorsum[color] - sizesum[size] + size;
 
            pre[0= idx;
            pre[1= color;
            pre[2= size;
        }
 
        StringBuffer sb = new StringBuffer();
        for (int i = 1; i <= N; i++) {
            sb.append(ans[i]).append("\n");
        }
        System.out.println(sb.toString());
    }
 
    static void input() throws Exception {
        int x, y;
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        list = new ArrayList<>();
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
            x = Integer.parseInt(st.nextToken());
            y = Integer.parseInt(st.nextToken());
            list.add(new Pair(i, x, y));
        }
 
        Collections.sort(list, new Comparator<Pair>() {
            @Override
            public int compare(Pair o1, Pair o2) {
                if (o1.size == o2.size)
                    return o1.color - o2.color;
                else
                    return o1.size - o2.size;
            }
        });
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 13325 이진 트리  (0) 2021.06.18
boj 1563 개근상  (0) 2021.06.02
boj 12869 뮤탈리스크  (0) 2021.04.04
boj 1520 내리막 길  (0) 2021.03.28
boj 1937 욕심쟁이 판다  (0) 2021.03.28

www.acmicpc.net/problem/2573

 

2573번: 빙산

첫 줄에는 이차원 배열의 행의 개수와 열의 개수를 나타내는 두 정수 N과 M이 한 개의 빈칸을 사이에 두고 주어진다. N과 M은 3 이상 300 이하이다. 그 다음 N개의 줄에는 각 줄마다 배열의 각 행을

www.acmicpc.net

먼저 빙산 주위에 바다가 있는 위치 수만큼 빙산이 녹습니다.

 

이중for문으로 이거를 확인해주시면 되고, 주위에 바다가 있을 때마다 cnt[i][j]를 1씩 늘려줍니다.

그 다음 이중for문을 다시 돌려서 cnt[i][j]만큼 빙산을 녹여줍니다.

 

빙산을 녹이는 과정에서 빙산이 두 덩어리 이상으로 분리가 되면 그 시간을 출력해주시면 됩니다.

이 과정을 bfs로 구현하였습니다. 이중for문을 돌면서 방문안된 빙산을 발견하면 bfs를 호출하는데

만약 두 번째로 bfs에 들어가게 되면 빙산이 분리가 되었다는 말이 되기때문에 바로 시간을 출력해주시면 됩니다.

 

저는 문제를 읽어보니 최초로 주어지는 입력에는 무조건 빙산이 한 덩어리라는 조건이 없어서

빙산이 두 덩어리 이상으로 분리가 되었는지 체크하는 bfs함수를 먼저 호출하였습니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static int list[][] = new int[300][300];
    static int cnt[][] = new int[300][300];
    static boolean visit[][] = new boolean[300][300];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static int N, M;
 
    static void init() {
        for (int i = 0; i < N; i++)
            Arrays.fill(visit[i], false);
    }
 
    static void bfs(int sx, int sy) {
        Deque<int[]> dq = new ArrayDeque<>();
        dq.add(new int[] { sx, sy });
        visit[sx][sy] = true;
        while (!dq.isEmpty()) {
            int x = dq.peek()[0];
            int y = dq.poll()[1];
 
            for (int i = 0; i < 4; i++) {
                int nx = x + direct[i][0];
                int ny = y + direct[i][1];
 
                if (visit[nx][ny] || list[nx][ny] == 0)
                    continue;
 
                dq.add(new int[] { nx, ny });
                visit[nx][ny] = true;
            }
        }
    }
 
    static void func() {
        for (int t = 0;; t++) {
            boolean chk = false;
 
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (list[i][j] == 0 || visit[i][j])
                        continue;
                    if (chk) {
                        System.out.println(t);
                        return;
                    }
                    bfs(i, j);
                    chk = true;
                }
            }
 
            if (!chk) {
                System.out.println(0);
                return;
            }
 
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (list[i][j] == 0)
                        continue;
                    for (int k = 0; k < 4; k++) {
                        int nx = i + direct[k][0];
                        int ny = j + direct[k][1];
 
                        if (list[nx][ny] == 0)
                            cnt[i][j]++;
                    }
                }
            }
 
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (list[i][j] == 0)
                        continue;
                    list[i][j] = list[i][j] >= cnt[i][j] ? list[i][j] - cnt[i][j] : 0;
                    cnt[i][j] = 0;
                }
            }
            
            init();
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < M; j++) {
                list[i][j] = Integer.parseInt(st.nextToken());
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 1194 달이 차오른다, 가자.  (0) 2021.04.21
boj 17471 게리맨더링  (0) 2021.04.16
boj 14923 미로 탈출  (0) 2021.03.29
boj 17836 공주님을 구해라!  (0) 2021.03.26
boj 9205 맥주 마시면서 걸어가기  (0) 2021.03.25

www.acmicpc.net/problem/1043

 

1043번: 거짓말

지민이는 파티에 가서 이야기 하는 것을 좋아한다. 파티에 갈 때마다, 지민이는 지민이가 가장 좋아하는 이야기를 한다. 지민이는 그 이야기를 말할 때, 있는 그대로 진실로 말하거나 엄청나게

www.acmicpc.net

이야기의 진실을 아는사람과 같은 파티에 참석하는 사람들에게는 거짓말을 하면 안됩니다.

저는 이를 union-find로 만나는 모든 사람들을 체크해주었습니다.

 

각 파티에 모이는 사람들을 union-find로 같이 묶어주면서

진실을 아는 사람과 모르는 사람이 만날 때 둘 다 진실을 아는 것으로 판단하였습니다.

 

최종으로 M개의 파티를 돌면서 find(x)가 모두 false면 거짓말을 할 수 있고, 아니면 진실만을 얘기해야합니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static int parent[] = new int[51];
    static ArrayList<Integer> list[] = new ArrayList[51];
    static boolean know[] = new boolean[51];
    static int N, M, K;
 
    static int find(int v) {
        if (parent[v] == v)
            return v;
        return parent[v] = find(parent[v]);
    }
 
    static void Union(int u, int v) {
        int x = find(u);
        int y = find(v);
 
        parent[y] = x;
        if (know[y]) {
            know[x] = true;
        }
    }
    
    static void func() {
        int ans = 0;
        for (int i = 0; i < M; i++) {
            boolean chk = true;
            for (int j = 0; j < list[i].size(); j++) {
                int x = list[i].get(j);
 
                if (know[find(x)]) {
                    chk = false;
                    break;
                }
            }
 
            if (chk)
                ans++;
        }
        
        System.out.println(ans);
    }
 
    static void init() {
        for (int i = 1; i <= N; i++) {
            parent[i] = i;
        }
    }
 
    static void input() throws Exception {
        int x;
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        init();
 
        st = new StringTokenizer(br.readLine());
        K = Integer.parseInt(st.nextToken());
        for (int i = 0; i < K; i++) {
            x = Integer.parseInt(st.nextToken());
            know[x] = true;
        }
 
        for (int i = 0; i < M; i++) {
            int u = -1, v;
            list[i] = new ArrayList<>();
            st = new StringTokenizer(br.readLine());
            K = Integer.parseInt(st.nextToken());
            for (int j = 0; j < K; j++) {
                v = Integer.parseInt(st.nextToken());
                list[i].add(v);
                if (u == -1) {
                    u = v;
                    continue;
                }
                Union(u, v);
                u = v;
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

'algorithm > Union-Find' 카테고리의 다른 글

boj 20040 사이클 게임  (0) 2021.06.27
boj 10775 공항  (0) 2021.03.17
boj 4195 친구 네트워크  (0) 2021.03.17
boj 1976 여행 가자  (0) 2021.03.17
boj 1717 집합의 표현  (0) 2021.02.06

www.acmicpc.net/problem/12869

 

12869번: 뮤탈리스크

1, 3, 2 순서대로 공격을 하면, 남은 체력은 (12-9, 10-1, 4-3) = (3, 9, 1)이다. 2, 1, 3 순서대로 공격을 하면, 남은 체력은 (0, 0, 0)이다.

www.acmicpc.net

dp[hp1][hp2][hp3] : SCV의 체력이 각각 hp1, hp2, hp3 남았을 때 공격해야할 횟수의 최솟값

 

뮤탈리스크는 일반적으로 한 번 공격할 때 3기의 SCV를 공격할 수 있습니다.

 

스타크래프트에서는 9, 6, 3 순서대로 데미지가 들어가지만 이 문제에서는 9, 3, 1 순서대로 데미지가 들어갑니다.

(이거를 쿠션데미지라고 합니다.)

 

SCV의 체력이 0이하가 되면 파괴되고, 한 번의 공격에서 같은 SCV를 두 번이상 공격할 수 없습니다.

1번 SCV를 먼저 공격했을 때 쿠션데미지를 2번, 3번 순으로 넣을 때 / 3번, 2번 순으로 넣을 때를 각각 구해줍니다.

마찬가지로 2번, 3번 SCV를 먼저 공격했을 때도 쿠션데미지를 넣는 경우를 각각 구해줍니다.

 

정리하자면

1 -> 2 -> 3

1 -> 3 -> 2

 

2 -> 1 -> 3

2 -> 3 -> 1

 

3 -> 1 -> 2

3 -> 2 -> 1

위의 순서를 모두 구한 것의 최솟값을 출력해주시면 됩니다.

재귀를 돌리는 도중에 체력이 0이하가 되면 0으로 맞춰줘야합니다. (배열의 음수인덱스 참조 가능성)

 

 

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
#include <iostream>
#include <cstring>
#include <algorithm>
#define INF 2147483647
using namespace std;
 
int dp[61][61][61];
int list[3];
int N;
 
int sub(int x, int y) {
    return x > y ? x - y : 0;
}
 
int func(int hp1, int hp2, int hp3) {
    if (!hp1 && !hp2 && !hp3) return 0;
    
    int &ret = dp[hp1][hp2][hp3];
    if (ret != -1return ret;
    ret = INF;
 
    if (hp1) {
        ret = min(ret, func(sub(hp1, 9), sub(hp2, 3), sub(hp3, 1)) + 1);
        ret = min(ret, func(sub(hp1, 9), sub(hp2, 1), sub(hp3, 3)) + 1);
    }
 
    if (hp2) {
        ret = min(ret, func(sub(hp1, 3), sub(hp2, 9), sub(hp3, 1)) + 1);
        ret = min(ret, func(sub(hp1, 1), sub(hp2, 9), sub(hp3, 3)) + 1);
    }
 
    if (hp3) {
        ret = min(ret, func(sub(hp1, 3), sub(hp2, 1), sub(hp3, 9)) + 1);
        ret = min(ret, func(sub(hp1, 1), sub(hp2, 3), sub(hp3, 9)) + 1);
    }
 
    return ret;
}
 
void input() {
    cin >> N;
    for (int i = 0; i < N; i++) {
        cin >> list[i];
    }
 
    memset(dp, -1sizeof(dp));
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    cout << func(list[0], list[1], list[2]) << '\n';
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 1563 개근상  (0) 2021.06.02
boj 10800 컬러볼  (0) 2021.04.09
boj 1520 내리막 길  (0) 2021.03.28
boj 1937 욕심쟁이 판다  (0) 2021.03.28
boj 2201 이친수 찾기  (2) 2021.03.24

www.acmicpc.net/problem/1626

 

1626번: 두 번째로 작은 스패닝 트리

첫째 줄에 그래프의 정점의 수 V(1 ≤ V ≤ 50,000)와 간선의 수 E(1 ≤ E ≤ 200,000)가 들어온다. 둘째 줄부터 E+1번째 줄까지 한 간선으로 연결된 두 정점과 그 간선의 가중치가 주어진다. 가중치는 100,

www.acmicpc.net

생애 첫 다이아문제 AC라 기분이 좋군요 ㅎㅎ

 

emoney96.tistory.com/193

 

boj 15481 그래프와 MST

www.acmicpc.net/problem/15481 15481번: 그래프와 MST 첫째 줄에 정점의 개수 N과 간선의 개수 M (2 ≤ N ≤ 200,000, N-1 ≤ M ≤ 200,000) 둘째 줄부터 M개의 줄에 간선의 정보 u, v, w가 주어진다. u와 v를..

emoney96.tistory.com

이 문제를 풀기 전에 그래프와 MST 문제를 풀어봐야합니다. (풀이가 비슷합니다.)

 

 

두 번째로 작은 스패닝 트리는 최소 스패닝 트리에서 하나의 간선만 바꿔주면 됩니다.

즉, 하나의 간선이 다릅니다.

 

1. 먼저 주어진 간선들로 첫 번째 mst를 구합니다.

2. 첫 번째 mst에 사용된 간선들로 인접 리스트를 만듭니다.

3. 인접 리스트의 depth를 구합니다.

4. 간선정보를 하나씩 가져와서 lca를 각각 구합니다.

5. mst - lca(u, v) + w의 최소를 구합니다.

 

여기까지는 그래프와 MST문제와 별다를게 없지만 이문제와의 차이점이 있습니다.

1. 두 번째 mst가 첫 번째 mst보다 커야함 -> 두 번째 mst를 구하지 못할 수 있음

2. 첫 번째 mst조차 구하지 못할 수 있음

 

위의 경우에는 -1을 출력해야합니다.

 

2번 경우를 확인할 때는 첫 번째 mst를 구할 때 고른 간선이 N - 1개인지 확인하는 것으로 예외처리 합니다.

1번 경우를 확인할 때는 lca로 u ~ v 경로의 간선을 구할 때

두개의 간선(가장 높은 가중치의 간선과 그 다음 높은 가중치의 간선)을 구합니다.

가장 높은 간선이 추가할 간선과 가중치가 같으면 1번조건에 걸리기 때문에 그 다음 높은 간선을 제거해야합니다.

 

마지막으로 ans가 최댓값이면 -1, 아니면 갱신된 값을 출력해줍니다.

 

정리하자면

1. 주어진 간선들로 첫 번째 mst를 구합니다.

2. 첫 번째 mst에 사용된 간선들로 인접 리스트를 만듭니다.

3. 인접 리스트의 depth를 구합니다.

4. lca(u, v)로 첫 번째, 두 번째 간선을 구합니다.

5. 구한 간선들이 w와 다를 경우에만 ans를 갱신합니다.

6. ans가 max값이면 -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
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define MAX 50000
#define LOG 20
using namespace std;
 
typedef struct edge {
    int u;
    int v;
    int w;
}edge;
 
vector<pair<intint> > list[MAX + 1];
vector<edge> v;
pair<intpair<intint> > lcaParent[MAX + 1][LOG];
int mstParent[MAX + 1], depth[MAX + 1];
bool visit[MAX + 1];
int mst;
int N, M, cnt;
 
bool cmp(edge a, edge b) {
    return a.w < b.w;
}
 
pair<intint> f(pair<intint> a, pair<intint> b) {
    vector<int> nv;
    nv.push_back(a.first);
    nv.push_back(a.second);
    nv.push_back(b.first);
    nv.push_back(b.second);
    sort(nv.rbegin(), nv.rend());
    nv.erase(unique(nv.begin(), nv.end()), nv.end());
    if (nv.size() < 2) nv.push_back(-1);
    return { nv[0], nv[1] };
}
 
void dfs(int v, int d) {
    depth[v] = d;
    visit[v] = true;
 
    for (int i = 0; i < list[v].size(); i++) {
        int next = list[v][i].first;
        int w = list[v][i].second;
 
        if (visit[next]) continue;
        lcaParent[next][0= { v,{w,-1} };
        dfs(next, d + 1);
    }
}
 
int find(int v) {
    if (mstParent[v] == v) return v;
    return mstParent[v] = find(mstParent[v]);
}
 
void Union(int x, int y, int w) {
    int a = find(x);
    int b = find(y);
 
    if (a == b) return;
    list[x].push_back({ y,w });
    list[y].push_back({ x,w });
    mstParent[b] = a;
    mst += w;
    cnt++;
}
 
void makeMst() {
    for (int i = 0; i < M; i++) {
        int x = v[i].u;
        int y = v[i].v;
        int w = v[i].w;
 
        Union(x, y, w);
        if (cnt == N - 1break;
    }
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        mstParent[i] = i;
    }
    memset(lcaParent, -1sizeof(lcaParent));
}
 
pair<intint> lca(int x, int y) {
    if (depth[x] > depth[y]) swap(x, y);
    pair<intint> ret = { -1,-1 };
 
    for (int i = LOG - 1; i >= 0; i--) {
        if (depth[y] - depth[x] >= (1 << i)) {
            ret = f(ret, lcaParent[y][i].second);
            
            y = lcaParent[y][i].first;
        }
    }
 
    if (x == y) return ret;
 
    for (int i = LOG - 1; i >= 0; i--) {
        if (lcaParent[x][i].first == 0continue;
        if (lcaParent[x][i].first != lcaParent[y][i].first) {
            ret = f(ret, lcaParent[x][i].second);
            ret = f(ret, lcaParent[y][i].second);
 
            x = lcaParent[x][i].first;
            y = lcaParent[y][i].first;
        }
    }
 
    ret = f(ret, lcaParent[x][0].second);
    ret = f(ret, lcaParent[y][0].second);
    
    return ret;
}
 
void func() {
    if (cnt < N - 1) {
        cout << "-1\n";
        return;
    }
 
    dfs(11);
    for (int j = 1; j < LOG; j++) {
        for (int i = 1; i <= N; i++) {
            lcaParent[i][j].first = lcaParent[lcaParent[i][j - 1].first][j - 1].first;
            if (lcaParent[i][j].first == -1continue;
            lcaParent[i][j].second = f(lcaParent[i][j - 1].second, lcaParent[lcaParent[i][j - 1].first][j - 1].second);
        }
    }
 
    long long ans = 2147483647;
    for (int i = 0; i < M; i++) {
        int x = v[i].u;
        int y = v[i].v;
        int w = v[i].w;
        pair<intint> sub = lca(x, y);
        
        if (sub.first != w && sub.first != -1) ans = min(ans, (long long)(mst - sub.first + w));
        else if (sub.second != w && sub.second != -1) ans = min(ans, (long long)(mst - sub.second + w));
    }
 
    if (ans >= 2147483647cout << "-1\n";
    else cout << ans << '\n';
}
 
void input() {
    int x, y;
    int w;
    cin >> N >> M;
    for (int i = 0; i < M; i++) {
        cin >> x >> y >> w;
        v.push_back({ x,y,w });
    }
    sort(v.begin(), v.end(), cmp);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    init();
    makeMst();
    func();
 
    return 0;
}
cs

'algorithm > LCA' 카테고리의 다른 글

boj 6059 Pasture Walking  (0) 2021.06.16
boj 3584 가장 가까운 공통 조상  (0) 2021.06.16
boj 15481 그래프와 MST  (0) 2021.04.01
boj 15480 LCA와 쿼리  (0) 2021.02.14
boj 11438 LCA 2  (0) 2021.02.11

www.acmicpc.net/problem/15481

 

15481번: 그래프와 MST

첫째 줄에 정점의 개수 N과 간선의 개수 M (2 ≤ N ≤ 200,000, N-1 ≤ M ≤ 200,000) 둘째 줄부터 M개의 줄에 간선의 정보 u, v, w가 주어진다. u와 v를 연결하는 간선의 가중치가 w라는 뜻이다. (1 ≤ u, v ≤

www.acmicpc.net

M개의 간선 정보가 들어오는데 i번째 간선을 포함한 MST를 출력하는 문제입니다.

 

우선 전체 MST를 구해줍니다.

그 다음 i번째 간선을 포함해주고 그 간선에 연결된 정점들의 경로에 있는 MST 간선을 하나 제거해야합니다.

이 경로를 순회해야 하기때문에 이를 LCA로 구합니다.

 

여기서 LCA를 구하기 전에 각 정점의 높이를 구해야하는데 인접 리스트를 MST 간선들만 가지고 구해줍니다.

그럼 u v 경로의 최대 간선을 구할 수 있습니다.

 

답은 mst - lca(u, v) + w을 출력해주시면 되고, 입력이 들어온 순서대로 출력해야하니 인덱스를 유지해야합니다.

 

정리하자면

1. 먼저 주어진 간선들로 MST를 구합니다.

2. MST에 사용된 간선들로 인접 리스트를 만들어줍니다.

3. 인접리스트의 depth를 구합니다.

4. 입력(간선 정보)이 들어왔던 순서대로 lca를 구해줍니다.

5. mst - lca(u, v) + w을 출력합니다.

 

 

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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <iostream>
#include <vector>
#include <algorithm>
#define MAX 200000
#define LOG 20
using namespace std;
typedef long long ll;
 
typedef struct edge {
    int u;
    int v;
    ll w;
}edge;
 
vector<pair<int, ll> > list[MAX + 1];
vector<edge> v, nv;
pair<int, ll> lcaParent[MAX + 1][LOG];
int mstParent[MAX + 1], depth[MAX + 1];
bool visit[MAX + 1];
ll mst;
int N, M, cnt;
 
bool cmp(edge a, edge b) {
    return a.w < b.w;
}
 
void dfs(int v, int d) {
    depth[v] = d;
    visit[v] = true;
 
    for (int i = 0; i < list[v].size(); i++) {
        int next = list[v][i].first;
        ll w = list[v][i].second;
 
        if (visit[next]) continue;
        lcaParent[next][0= { v,w };
        dfs(next, d + 1);
    }
}
 
int find(int v) {
    if (mstParent[v] == v) return v;
    return mstParent[v] = find(mstParent[v]);
}
 
void Union(int x, int y, ll w) {
    int a = find(x);
    int b = find(y);
 
    if (a == b) return;
    list[x].push_back({ y,w });
    list[y].push_back({ x,w });
    mstParent[b] = a;
    mst += w;
    cnt++;
}
 
void makeMst() {
    for (int i = 0; i < M; i++) {
        int x = nv[i].u;
        int y = nv[i].v;
        ll w = nv[i].w;
 
        Union(x, y, w);
        if (cnt == N - 1break;
    }
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        mstParent[i] = i;
    }
}
 
ll lca(int x, int y) {
    if (depth[x] > depth[y]) swap(x, y);
    ll ret = 0;
 
    for (int i = LOG - 1; i >= 0; i--) {
        if (depth[y] - depth[x] >= (1 << i)) {
            ret = max(ret, lcaParent[y][i].second);
            y = lcaParent[y][i].first;
        }
    }
 
    if (x == y) return ret;
 
    for (int i = LOG - 1; i >= 0; i--) {
        if (lcaParent[x][i].first == 0continue;
        if (lcaParent[x][i].first != lcaParent[y][i].first) {
            ret = max(ret, max(lcaParent[x][i].second, lcaParent[y][i].second));
 
            x = lcaParent[x][i].first;
            y = lcaParent[y][i].first;
        }
    }
 
    return max(ret, max(lcaParent[x][0].second, lcaParent[y][0].second));
}
 
void func() {
    dfs(11);
    for (int j = 1; j < LOG; j++) {
        for (int i = 1; i <= N; i++) {
            lcaParent[i][j].first = lcaParent[lcaParent[i][j - 1].first][j - 1].first;
            lcaParent[i][j].second = max(lcaParent[i][j - 1].second, lcaParent[lcaParent[i][j - 1].first][j - 1].second);
        }
    }
 
    for (int i = 0; i < M; i++) {
        int x = v[i].u;
        int y = v[i].v;
        ll w = v[i].w;
        ll sub = lca(x, y);
        cout << mst - sub + w << '\n';
    }
}
 
void input() {
    int x, y;
    ll w;
    cin >> N >> M;
    for (int i = 0; i < M; i++) {
        cin >> x >> y >> w;
        v.push_back({ x,y,w });
    }
    nv = v;
    sort(nv.begin(), nv.end(), cmp);
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    init();
    makeMst();
    func();
 
    return 0;
}
cs

'algorithm > LCA' 카테고리의 다른 글

boj 3584 가장 가까운 공통 조상  (0) 2021.06.16
boj 1626 두 번째로 작은 스패닝 트리  (0) 2021.04.02
boj 15480 LCA와 쿼리  (0) 2021.02.14
boj 11438 LCA 2  (0) 2021.02.11
boj 11437 LCA  (0) 2021.02.11

www.acmicpc.net/problem/17609

 

17609번: 회문

각 문자열이 회문인지, 유사 회문인지, 둘 모두 해당되지 않는지를 판단하여 회문이면 0, 유사 회문이면 1, 둘 모두 아니면 2를 순서대로 한 줄에 하나씩 출력한다.

www.acmicpc.net

N이 10만개니 lcs로는 해결 못합니다..

 

투 포인터로 하나하나 확인해줍니다.

왼쪽 인덱스를 0, 오른쪽 인덱스를 ch.length - 1로 두고

문자열의 끝 단어끼리 비교를 합니다.

 

1. 끝 단어가 같을 때

- 왼쪽, 오른쪽 인덱스 모두 다음 인덱스를 확인합니다.

2. 끝 단어가 다를 때

- 왼쪽 인덱스를 옮겨줄 때와 오른쪽 인덱스를 옮겨줄 때를 각각 확인합니다.

저는 투포인터를 두번 사용하여 왼쪽 인덱스를 옮길 때, 오른쪽 인덱스를 옮길 때 다른 값의 min값으로 답을 출력하였습니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static StringBuffer sb = new StringBuffer();
    static char ch[];
 
    static void func() {
        int l = 0;
        int r = ch.length - 1;
        int ans = 0;
        int cnt = 0;
        while (l < r) {
            if (ch[l] == ch[r]) {
                l++;
                r--;
            } else {
                cnt++;
                l++;
            }
 
            if (cnt == 2)
                break;
        }
        ans = cnt;
 
        l = 0;
        r = ch.length - 1;
        cnt = 0;
        while (l < r) {
            if (ch[l] == ch[r]) {
                l++;
                r--;
            } else {
                cnt++;
                r--;
            }
 
            if (cnt == 2)
                break;
        }
 
        ans = Math.min(ans, cnt);
        sb.append(ans).append("\n");
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        ch = st.nextToken().toCharArray();
    }
 
    public static void main(String[] args) throws Exception {
        st = new StringTokenizer(br.readLine());
        int tc = Integer.parseInt(st.nextToken());
        while (tc-- > 0) {
            input();
            func();
        }
        System.out.println(sb.toString());
    }
}
cs

'algorithm > Two-Pointer' 카테고리의 다른 글

boj 1253 좋다  (0) 2021.10.21
boj 9024 두 수의 합  (0) 2021.10.21
boj 2559 수열  (0) 2021.02.12
boj 1806 부분합  (0) 2021.01.22
boj 2003 수들의 합 2  (0) 2021.01.22

www.acmicpc.net/problem/14923

 

14923번: 미로 탈출

홍익이는 사악한 마법사의 꾐에 속아 N x M 미로 (Hx, Hy) 위치에 떨어졌다. 다행히도 홍익이는 마법사가 만든 미로의 탈출 위치(Ex, Ey)를 알고 있다. 하지만 미로에는 곳곳에 마법사가 설치한 벽이

www.acmicpc.net

(hx, hy)에서 출발하여 (ex, ey)까지 갈 수 있는 최단거리를 출력합니다.

맵에는 벽이 있으며 벽을 1개까지 부술 수 있습니다.

 

www.acmicpc.net/problem/2206

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로

www.acmicpc.net

이 문제와 같은 풀이방식입니다.

이 문제와 다른점은 출발점과 도착점이 고정이 아니라는 점입니다.

 

visit[x][y][cnt] : (x, y)에 벽을 부수고 방문한 경우와 안부수고 방문한 경우를 나눠줍니다.

 

탈출이 가능하면 거리를 출력, 불가능하면 -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
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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static Deque<int[]> dq = new ArrayDeque<>();
    static int list[][] = new int[1001][1001];
    static boolean visit[][][] = new boolean[1001][1001][2];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static int N, M, ex, ey;
 
    static void bfs() {
        for (int t = 1;; t++) {
            int size = dq.size();
            while (size-- > 0) {
                int x = dq.peek()[0];
                int y = dq.peek()[1];
                int cnt = dq.poll()[2];
 
                for (int i = 0; i < 4; i++) {
                    int nx = x + direct[i][0];
                    int ny = y + direct[i][1];
 
                    if (nx < 1 || ny < 1 || nx > N || ny > M)
                        continue;
                    if (list[nx][ny] == 1) {
                        if (cnt > 0 || visit[nx][ny][1])
                            continue;
 
                        dq.add(new int[] { nx, ny, 1 });
                        visit[nx][ny][1= true;
                    } else {
                        if (visit[nx][ny][cnt])
                            continue;
 
                        dq.add(new int[] { nx, ny, cnt });
                        visit[nx][ny][cnt] = true;
 
                        if (nx == ex && ny == ey) {
                            System.out.println(t);
                            return;
                        }
                    }
                }
            }
 
            if (dq.isEmpty()) {
                System.out.println(-1);
                return;
            }
        }
    }
 
    static void input() throws Exception {
        int x, y;
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
 
        st = new StringTokenizer(br.readLine());
        x = Integer.parseInt(st.nextToken());
        y = Integer.parseInt(st.nextToken());
        dq.add(new int[] { x, y, 0 });
        visit[x][y][0= true;
 
        st = new StringTokenizer(br.readLine());
        x = Integer.parseInt(st.nextToken());
        y = Integer.parseInt(st.nextToken());
        ex = x;
        ey = y;
 
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 1; j <= M; j++) {
                list[i][j] = Integer.parseInt(st.nextToken());
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        bfs();
    }
}
cs

'algorithm > bfs' 카테고리의 다른 글

boj 17471 게리맨더링  (0) 2021.04.16
boj 2573 빙산  (0) 2021.04.05
boj 17836 공주님을 구해라!  (0) 2021.03.26
boj 9205 맥주 마시면서 걸어가기  (0) 2021.03.25
boj 1600 말이 되고픈 원숭이  (0) 2021.03.24

www.acmicpc.net/problem/1520

 

1520번: 내리막 길

첫째 줄에는 지도의 세로의 크기 M과 가로의 크기 N이 빈칸을 사이에 두고 주어진다. 이어 다음 M개 줄에 걸쳐 한 줄에 N개씩 위에서부터 차례로 각 지점의 높이가 빈 칸을 사이에 두고 주어진다.

www.acmicpc.net

emoney96.tistory.com/189

 

boj 1937 욕심쟁이 판다

www.acmicpc.net/problem/1937 1937번: 욕심쟁이 판다 n*n의 크기의 대나무 숲이 있다. 욕심쟁이 판다는 어떤 지역에서 대나무를 먹기 시작한다. 그리고 그 곳의 대나무를 다 먹어 치우면 상, 하, 좌, 우 중

emoney96.tistory.com

이 문제와 비슷한 풀이입니다.

dfs + dp를 사용하며

위의 문제는 칸의 수를 세어주었지만 이 문제는 (0, 0)에서 (N - 1, M - 1)까지 도달할 수 있는 경우의 수를 세어주는 문제입니다.

 

현재 칸보다 높이가 더 낮은 지점으로만 이동합니다.

(N - 1, M - 1)에 도달하면 1을 리턴하고 이미 방문한 좌표에는 해당 좌표의 dp[x][y]를 리턴해줍니다.

 

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static int list[][] = new int[500][500];
    static int dp[][] = new int[500][500];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static int N, M;
 
    static int func(int x, int y) {
        if (x == N - 1 && y == M - 1)
            return 1;
        if (dp[x][y] != -1)
            return dp[x][y];
        dp[x][y] = 0;
 
        for (int i = 0; i < 4; i++) {
            int nx = x + direct[i][0];
            int ny = y + direct[i][1];
 
            if (nx < 0 || ny < 0 || nx >= N || ny >= M)
                continue;
            if (list[x][y] <= list[nx][ny])
                continue;
 
            dp[x][y] += func(nx, ny);
        }
        
        return dp[x][y];
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        for (int i = 0; i < N; i++) {
            Arrays.fill(dp[i], -1);
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < M; j++) {
                list[i][j] = Integer.parseInt(st.nextToken());
            }
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        System.out.println(func(00));
    }
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 10800 컬러볼  (0) 2021.04.09
boj 12869 뮤탈리스크  (0) 2021.04.04
boj 1937 욕심쟁이 판다  (0) 2021.03.28
boj 2201 이친수 찾기  (2) 2021.03.24
boj 2228 구간 나누기  (0) 2021.03.21

+ Recent posts