www.acmicpc.net/problem/1937

 

1937번: 욕심쟁이 판다

n*n의 크기의 대나무 숲이 있다. 욕심쟁이 판다는 어떤 지역에서 대나무를 먹기 시작한다. 그리고 그 곳의 대나무를 다 먹어 치우면 상, 하, 좌, 우 중 한 곳으로 이동을 한다. 그리고 또 그곳에서

www.acmicpc.net

판다는 4방향으로 다닐 수 있지만 대나무의 양이 현재보다 더 많은 곳으로 가야합니다.

완전 탐색을 하면 답을 찾을 수는 있지만 N의 범위가 500까지이므로 시간초과가 날 것입니다.

 

따라서 이 문제는 dfs + dp 문제입니다.

이미 팬더가 지나간 길에 대해서 다시 탐색할 필요가 없으므로 dp를 사용합니다.

dp[x][y] : (x, y)를 시작점으로 판다가 최대한 살 수 있는 일수

 

dfs에 dp가 추가된 간단한 문제였습니다.

 

 

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
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[501][501];
    static int dp[][] = new int[501][501];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 } };
    static int N, ans;
 
    static int dfs(int x, int y) {
        if (dp[x][y] != -1)
            return dp[x][y];
        dp[x][y] = 1;
 
        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 >= N)
                continue;
            if (list[x][y] >= list[nx][ny])
                continue;
 
            dp[x][y] = Math.max(dp[x][y], dfs(nx, ny) + 1);
        }
 
        ans = Math.max(ans, dp[x][y]);
        return dp[x][y];
    }
 
    static void func() {
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (dp[i][j] != -1)
                    continue;
                dfs(i, j);
            }
        }
        System.out.println(ans);
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = 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 < N; j++) {
                list[i][j] = Integer.parseInt(st.nextToken());
            }
        }
 
    }
 
    public static void main(String[] args) throws Exception {
        input();
        func();
    }
}
cs

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

boj 12869 뮤탈리스크  (0) 2021.04.04
boj 1520 내리막 길  (0) 2021.03.28
boj 2201 이친수 찾기  (2) 2021.03.24
boj 2228 구간 나누기  (0) 2021.03.21
boj 1695 팰린드롬 만들기  (0) 2021.03.20

www.acmicpc.net/problem/17836

 

17836번: 공주님을 구해라!

용사는 마왕이 숨겨놓은 공주님을 구하기 위해 (N, M) 크기의 성 입구 (1,1)으로 들어왔다. 마왕은 용사가 공주를 찾지 못하도록 성의 여러 군데 마법 벽을 세워놓았다. 용사는 현재의 가지고 있는

www.acmicpc.net

시작점 : (1, 1)

도착점 : (N, M)

제한 시간 : T

무기가 없으면 벽을 지나갈 수 없지만 무기가 있으면 모든 벽을 부수고 지나갈 수 있습니다.


visit[x][y][chk] : x, y에 도달했을 때 무기를 가진 상태로 방문했는지 여부

 

1. 다음 칸이 무기가 있는 칸일 경우(list[nx][ny] = 2)

- 무기를 획득하였으므로 chk=true인 값을 큐에 넣어줍니다.

2. 다음 칸이 벽이 아니고 방문하지 않았을 경우

- 평상시 bfs처럼 다음 정점을 큐에 넣고 방문체크합니다.

3. 다음 칸이 벽이고 무기를 가진 상태인 경우

- 무기를 갖고있으면 어디든 지나갈 수 있으므로 2번과 같은 로직을 수행합니다.

 

도착지점인 (N, M)의 값은 0이므로 2, 3번에서 (N, M)에 도달하였으면 현재 시간을 출력합니다.

만약 T시간 동안 (N, M)에 도달하지 못하면 Fail을 출력합니다.

 

 

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
#include <iostream>
#include <queue>
using namespace std;
 
typedef struct Point {
    int x;
    int y;
    bool chk;
};
 
queue<Point> q;
bool visit[101][101][2];
int list[101][101];
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
int N, M, T;
 
void bfs() {
    q.push({ 1,1,false });
    visit[1][1][0= true;
    for (int t = 1; t <= T; t++) {
        int qsize = q.size();
        while (qsize--) {
            int x = q.front().x;
            int y = q.front().y;
            bool chk = q.front().chk;
            q.pop();
 
            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] == 2 && !visit[nx][ny][1]) {
                    q.push({ nx,ny,true });
                    visit[nx][ny][1= true;
                }
                else if (list[nx][ny] == 0 && !visit[nx][ny][chk]) {
                    q.push({ nx,ny,chk });
                    visit[nx][ny][chk] = true;
                    if (nx == N && ny == M) {
                        cout << t << '\n';
                        return;
                    }
                }
                else if (list[nx][ny] == 1 && chk && !visit[nx][ny][chk]) {
                    q.push({ nx,ny,chk });
                    visit[nx][ny][chk] = true;
                    if (nx == N && ny == M) {
                        cout << t << '\n';
                        return;
                    }
                }
            }
        }
    }
 
    cout << "Fail\n";
}
 
void input() {
    cin >> N >> M >> T;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            cin >> list[i][j];
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    bfs();
 
    return 0;
}
cs

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

boj 2573 빙산  (0) 2021.04.05
boj 14923 미로 탈출  (0) 2021.03.29
boj 9205 맥주 마시면서 걸어가기  (0) 2021.03.25
boj 1600 말이 되고픈 원숭이  (0) 2021.03.24
boj 2589 보물섬  (0) 2021.03.16

www.acmicpc.net/problem/9205

 

9205번: 맥주 마시면서 걸어가기

송도에 사는 상근이와 친구들은 송도에서 열리는 펜타포트 락 페스티벌에 가려고 한다. 올해는 맥주를 마시면서 걸어가기로 했다. 출발은 상근이네 집에서 하고, 맥주 한 박스를 들고 출발한다.

www.acmicpc.net

1번 정점 : 시작점

2번 ~ N + 1번 정점 : 편의점

N + 2번 정점 : 도착점

 

bfs와 플로이드 와샬 두 가지 방법을 이용할 수 있습니다.

 

먼저 bfs 풀이로는 N^2으로 각 정점들 사이의 거리가 1000이하인 간선만 그래프화 시켜줍니다.

그 다음 1번정점으로 시작하여 bfs로 인접한 모든 정점을 방문한 후에 N + 2번 정점을 방문하였는지 확인합니다.

N + 2번 정점을 방문 하였으면 happy, 방문 안했으면 sad를 출력합니다.

 

 

플로이드 풀이로는 N^2으로 각 정점들 사이의 거리가 1000이하면 dis[i][j] = true를 하여 간선체크를 해줍니다.

그 다음 플로이드를 사용하는데 i ~ k번을 지나갈 수 있고, k ~ j번을 지나갈 수 있으면 i ~ j번을 지나갈 수 있습니다.

따라서 dis[i][k] && dis[k][j]이면 dis[i][j] = true를 해줍니다.

dis[1][N+2] = true면 happy, false면 sad를 출력합니다.

 

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
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 StringBuffer sb = new StringBuffer();
    static ArrayList<Integer> graph[] = new ArrayList[103];
    static boolean visit[] = new boolean[103];
    static int list[][] = new int[103][2];
    static int N;
 
    static void bfs() {
        Deque<Integer> dq = new ArrayDeque<>();
        dq.add(1);
        visit[1= true;
        while (!dq.isEmpty()) {
            int x = dq.poll();
 
            for (int i = 0; i < graph[x].size(); i++) {
                int next = graph[x].get(i);
 
                if (visit[next])
                    continue;
 
                dq.add(next);
                visit[next] = true;
            }
        }
 
        if (visit[N + 2])
            sb.append("happy\n");
        else
            sb.append("sad\n");
    }
 
    static boolean getDis(int a[], int b[]) {
        return (Math.abs(a[0- b[0]) + Math.abs(a[1- b[1])) <= 1000 ? true : false;
    }
 
    static void func() {
        for (int i = 1; i <= N + 1; i++) {
            for (int j = i + 1; j <= N + 2; j++) {
                if (getDis(list[i], list[j])) {
                    graph[i].add(j);
                    graph[j].add(i);
                }
            }
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        for (int i = 1; i <= N + 2; i++) {
            st = new StringTokenizer(br.readLine());
            list[i][0= Integer.parseInt(st.nextToken());
            list[i][1= Integer.parseInt(st.nextToken());
        }
    }
 
    static void init() {
        Arrays.fill(visit, false);
        for (int i = 1; i <= N + 2; i++) {
            graph[i] = new ArrayList<>();
        }
    }
 
    public static void main(String[] args) throws Exception {
        st = new StringTokenizer(br.readLine());
        int tc = Integer.parseInt(st.nextToken());
        while (tc-- > 0) {
            input();
            init();
            func();
            bfs();
        }
        System.out.println(sb.toString());
    }
}
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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 StringBuffer sb = new StringBuffer();
    static int list[][] = new int[103][2];
    static boolean dis[][] = new boolean[103][103];
    static int N;
 
    static int getDis(int x, int y, int tx, int ty) {
        return Math.abs(x - tx) + Math.abs(y - ty);
    }
 
    static void func() {
        for (int i = 1; i <= N + 1; i++) {
            for (int j = i + 1; j <= N + 2; j++) {
                if (getDis(list[i][0], list[i][1], list[j][0], list[j][1]) <= 1000) {
                    dis[i][j] = true;
                    dis[j][i] = true;
                }
            }
        }
 
        for (int k = 1; k <= N + 2; k++) {
            for (int i = 1; i <= N + 2; i++) {
                for (int j = 1; j <= N + 2; j++) {
                    if (dis[i][k] && dis[k][j])
                        dis[i][j] = true;
                }
            }
        }
 
        if (dis[1][N + 2])
            sb.append("happy\n");
        else
            sb.append("sad\n");
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        for (int i = 1; i <= N + 2; i++) {
            st = new StringTokenizer(br.readLine());
            list[i][0= Integer.parseInt(st.nextToken());
            list[i][1= Integer.parseInt(st.nextToken());
        }
    }
 
    static void init() {
        for (int i = 1; i <= N + 2; i++)
            Arrays.fill(dis[i], false);
    }
 
    public static void main(String[] args) throws Exception {
        st = new StringTokenizer(br.readLine());
        int tc = Integer.parseInt(st.nextToken());
        for (int t = 1; t <= tc; t++) {
            input();
            func();
            init();
        }
 
        System.out.println(sb.toString());
    }
}
cs

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

boj 14923 미로 탈출  (0) 2021.03.29
boj 17836 공주님을 구해라!  (0) 2021.03.26
boj 1600 말이 되고픈 원숭이  (0) 2021.03.24
boj 2589 보물섬  (0) 2021.03.16
boj 11559 Puyo Puyo  (0) 2021.02.26

www.acmicpc.net/problem/14938

 

14938번: 서강그라운드

예은이는 요즘 가장 인기가 있는 게임 서강그라운드를 즐기고 있다. 서강그라운드는 여러 지역중 하나의 지역에 낙하산을 타고 낙하하여, 그 지역에 떨어져 있는 아이템들을 이용해 서바이벌을

www.acmicpc.net

플로이드 와샬 알고리즘을 이용하여 각 정점에서부터의 최단거리를 모두 구해줍니다.

그리고 1 ~ N정점을 시작점으로 다른 정점과의 거리가 M 이하인 경우만 아이템 수를 더해줍니다.

다 더했으면 최댓값을 갱신해줍니다.

 

 

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
#include <iostream>
#include <algorithm>
#define INF 1000000000
using namespace std;
 
int dis[101][101], list[101];
int N, M, R;
 
void solve() {
    int ans = 0;
    for (int i = 1; i <= N; i++) {
        int sum = 0;
        for (int j = 1; j <= N; j++) {
            if (dis[i][j] > M) continue;
 
            sum += list[j];
        }
        ans = max(ans, sum);
    }
 
    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++){
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
            }
        }
    }
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (i == j) dis[i][j] = 0;
            else dis[i][j] = INF;
        }
    }
}
 
void input() {
    int u, v, w;
    cin >> N >> M >> R;
    init();
    for (int i = 1; i <= N; i++) {
        cin >> list[i];
    }
    while (R--) {
        cin >> u >> v >> w;
        dis[u][v] = w;
        dis[v][u] = w;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
    solve();
 
    return 0;
}
cs

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

boj 2273 줄 서기  (0) 2021.04.16

www.acmicpc.net/problem/1600

 

1600번: 말이 되고픈 원숭이

첫째 줄에 정수 K가 주어진다. 둘째 줄에 격자판의 가로길이 W, 세로길이 H가 주어진다. 그 다음 H줄에 걸쳐 W개의 숫자가 주어지는데, 0은 아무것도 없는 평지, 1은 장애물을 뜻한다. 장애물이 있

www.acmicpc.net

bfs 탐색인데 4방탐색에 위 사진과 같은 이동방식이 추가되었습니다.

위 사진처럼 말과 같이 움직일 수 있는 횟수가 K로 정해져있습니다. (0 <= K <= 30)

 

그러므로 방문체크는 3차원 배열로 해줍니다.

visit[x][y][k] : 말과 같이 움직인 횟수가 k번인 상태로 (x, y)에 도착한 경우

 

저는 방향탐색에 대한 좌표이동을 인덱스를 기준으로 나누었습니다.

1. 0 ~ 3번 인덱스 : 4방탐색

2. 4 ~ 11번 인덱스 : 말처럼 이동

4방탐색의 경우 k의 변화 없이 이동시켜줍니다.

말처럼 이동하는 경우 K미만으로 움직였을 경우에만 움직여줍니다.

 

(N - 1, M - 1)에 도달하였으면 시간을 출력합니다.

 

 

[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
#include <iostream>
#include <queue>
using namespace std;
 
queue<pair<pair<intint>pair<intint> > > q;
bool visit[200][200][31];
int map[200][200];
int x_direct[] = { 0,1,0,-1,-2,-1,1,2,2,1,-1,-2 }, y_direct[] = { 1,0,-1,0,1,2,2,1,-1,-2,-2,-1 };
int K, H, W, ans = -1;
 
void bfs() {
    while (!q.empty()) {
        int x = q.front().first.first;
        int y = q.front().first.second;
        int cnt = q.front().second.first;
        int horse = q.front().second.second;
        q.pop();
 
        if (x == H - 1 && y == W - 1) {
            ans = cnt;
            return;
        }
 
        for (int i = 0; i < 12; i++) {
            int xx = x + x_direct[i];
            int yy = y + y_direct[i];
 
            if (xx < 0 || yy < 0 || xx >= H || yy >= W) continue;
            if (map[xx][yy] == 1continue;
 
            if (x_direct[i] == 2 || x_direct[i] == -2 || y_direct[i] == 2 || y_direct[i] == -2) {
                if (visit[xx][yy][horse + 1|| horse == K) continue;
                q.push(make_pair(make_pair(xx, yy), make_pair(cnt + 1, horse + 1)));
                visit[xx][yy][horse + 1= true;
            }
            else {
                if (visit[xx][yy][horse]) continue;
                q.push(make_pair(make_pair(xx, yy), make_pair(cnt + 1, horse)));
                visit[xx][yy][horse] = true;
            }
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    cin >> K >> W >> H;
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            cin >> map[i][j];
        }
    }
 
    q.push(make_pair(make_pair(00), make_pair(00)));
    visit[0][0][0= true;
    bfs();
 
    cout << ans << '\n';
 
    return 0;
}
cs

 

 

[Java]

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
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 int list[][] = new int[201][201];
    static boolean visit[][][] = new boolean[201][201][31];
    static int direct[][] = { { 01 }, { 10 }, { 0-1 }, { -10 }, { 12 }, { 1-2 }, { -12 }, { -1-2 },
            { 21 }, { 2-1 }, { -21 }, { -2-1 } };
    static int N, M, K;
 
    static void bfs() {
        Deque<int[]> dq = new ArrayDeque<>();
        dq.add(new int[] { 000 });
        visit[0][0][0= true;
        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];
 
                if (x == N - 1 && y == M - 1) {
                    System.out.println(t - 1);
                    return;
                }
 
                for (int i = 0; i < 12; 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[nx][ny] == 1)
                        continue;
 
                    if (i < 4) {
                        if (visit[nx][ny][cnt])
                            continue;
                        dq.add(new int[] { nx, ny, cnt });
                        visit[nx][ny][cnt] = true;
                    } else {
                        if (cnt + 1 > K || visit[nx][ny][cnt + 1])
                            continue;
                        dq.add(new int[] { nx, ny, cnt + 1 });
                        visit[nx][ny][cnt + 1= true;
                    }
                }
            }
 
            if (dq.isEmpty()) {
                System.out.println(-1);
                return;
            }
        }
    }
 
    static void input() throws Exception {
        st = new StringTokenizer(br.readLine());
        K = Integer.parseInt(st.nextToken());
        st = new StringTokenizer(br.readLine());
        M = Integer.parseInt(st.nextToken());
        N = 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();
        bfs();
    }
}
cs

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

boj 17836 공주님을 구해라!  (0) 2021.03.26
boj 9205 맥주 마시면서 걸어가기  (0) 2021.03.25
boj 2589 보물섬  (0) 2021.03.16
boj 11559 Puyo Puyo  (0) 2021.02.26
boj 15653 구슬 탈출 4  (0) 2021.02.22

www.acmicpc.net/problem/2201

 

2201번: 이친수 찾기

0과 1로만 이루어진 수를 이진수라 한다. 이러한 이진수 들 특별한 성질을 갖는 것들이 있는데, 이들을 이친수(pinary number)라 한다. 이친수는 다음의 성질을 만족한다. 이친수는 0으로 시작하지 않

www.acmicpc.net

 

dp[length] : 길이가 length인 이친수의 시작 번호

 

1. 이친수는 0으로 시작하지 않는다.

2. 이친수에서는 1이 두 번 연속으로 나타나지 않는다. 즉, 11은 이친수가 아니다.

위 조건을 고려하여 길이당 이친수의 갯수는 피보나치 수열로 구할 수 있습니다.

 

저는 이를 이용하여 dp에 각 길이당 시작하는 번호를 담아놓습니다.

dp[1] = 1, dp[2] = 2, dp[3]= 3, dp[4] = 5, dp[5]=8, dp[6] = 13, ... 이런식으로 되고,

 

그리고 입력받은 N의 길이를 구합니다.

길이가 i일 때의 시작번호와 비교를 하여 dp[i] > N이면 length는 i - 1입니다.

 

그리고 length만큼 반복문을 돌려주면서 두 가지의 경우를 확인합니다.

1. dp[length] <= N이면 (번호 N이 length의 시작점보다 뒤에 있으면)

 => 1을 출력하고 N을 N의 시작번호만큼 빼줍니다.

 

2. dp[length] > N이면 (번호 N이 length의 시작점보다 앞에 있으면)

 => 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
#include <iostream>
using namespace std;
typedef long long ll;
 
ll dp[91], N;
 
void init() {
    dp[1= 1;
    dp[2= 2;
    for (int i = 3; i <= 90; i++) {
        dp[i] = dp[i - 1+ dp[i - 2];
    }
}
 
void solve() {
    int length = 0;
    for (int i = 1; i <= 90; i++) {
        if (dp[i] > N) {
            length = i - 1;
            break;
        }
    }
 
    while (length) {
        if (dp[length] <= N) {
            cout << 1;
            N -= dp[length];
        }
        else {
            cout << 0;
        }
        length--;
    }
    cout << '\n';
}
 
void input() {
    cin >> N;
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    init();
    input();
    solve();
 
    return 0;
}
cs

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

boj 1520 내리막 길  (0) 2021.03.28
boj 1937 욕심쟁이 판다  (0) 2021.03.28
boj 2228 구간 나누기  (0) 2021.03.21
boj 1695 팰린드롬 만들기  (0) 2021.03.20
boj 9177 단어 섞기  (0) 2021.03.19

www.acmicpc.net/problem/4485

 

4485번: 녹색 옷 입은 애가 젤다지?

젤다의 전설 게임에서 화폐의 단위는 루피(rupee)다. 그런데 간혹 '도둑루피'라 불리는 검정색 루피도 존재하는데, 이걸 획득하면 오히려 소지한 루피가 감소하게 된다! 젤다의 전설 시리즈의 주

www.acmicpc.net

 

다익스트라 기초에 2차원좌표가 추가되었습니다.

출발지점는 (0, 0)이고 도착지점은 (N - 1, N - 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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <queue>
#include <cstring>
#define INF 1000000000
using namespace std;
 
typedef struct Point {
    int x;
    int y;
    int dis;
}Point;
 
int list[125][125], d[125][125];
int direct[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
int N;
 
struct compare {
    bool operator()(Point a, Point b) {
        return a.dis > b.dis;
    }
};
 
void dijkstra() {
    priority_queue<Point, vector<Point>, compare> q;
    q.push({ 0,0,list[0][0] });
    d[0][0= list[0][0];
    while (!q.empty()) {
        int x = q.top().x;
        int y = q.top().y;
        int dis = q.top().dis;
        q.pop();
 
        if (d[x][y] < dis) continue;
 
        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 >= N) continue;
            int nextdis = dis + list[nx][ny];
            if (d[nx][ny] > nextdis) {
                d[nx][ny] = nextdis;
                q.push({ nx, ny, nextdis });
            }
        }
    }
}
 
void input() {
    cin >> N;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin >> list[i][j];
        }
    }
}
 
void init() {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            d[i][j] = INF;
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    for (int t = 1; ; t++) {
        input();
        if (!N) return 0;
        init();
        dijkstra();
        cout << "Problem " << t << ": " << d[N - 1][N - 1<< '\n';
    }
}
cs

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

boj 18352 특정 거리의 도시 찾기  (0) 2021.03.22
boj 14496 그대, 그머가 되어  (0) 2021.03.22

www.acmicpc.net/problem/18352

 

18352번: 특정 거리의 도시 찾기

첫째 줄에 도시의 개수 N, 도로의 개수 M, 거리 정보 K, 출발 도시의 번호 X가 주어진다. (2 ≤ N ≤ 300,000, 1 ≤ M ≤ 1,000,000, 1 ≤ K ≤ 300,000, 1 ≤ X ≤ N) 둘째 줄부터 M개의 줄에 걸쳐서 두 개

www.acmicpc.net

bfs와 다익스트라 두 가지방법 모두 사용하였습니다.

이 문제는 방향그래프이므로 u v 로 입력이 오면 u -> v로 받아야합니다.

 

먼저 다익스트라 알고리즘 방법으로는 가중치가 주어지지 않았기때문에 1로 두고 다익스트라 알고리즘을 이용하여 start에서 각 노드까지 최단거리를 다 구해줍니다.

최단거리가 K인 노드가 있으면 오름차순으로 출력해주고, 없으면 -1을 출력합니다.

 

bfs 방법으로는 start에서부터 시작하여 bfs를 K번 진행합니다.

bfs로 탐색하면서 각 노드까지의 거리를 갱신해줍니다.

최단거리가 K인 노드가 있으면 오름차순으로 출력해주고, 없으면 -1을 출력합니다.

 

다익스트라 사용
bfs 사용

 

다익스트라는 모든 정점까지의 최단거리를 다 구해주기 때문에 시간 상으로는 bfs가 훨씬 효율적입니다.

 

 

[dijkstra]

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
#include <iostream>
#include <queue>
#include <vector>
#define INF 1000000000
using namespace std;
 
vector<pair<intint> > list[300001];
int d[300001];
int N, M, K, start;
 
void solve() {
    bool chk = false;
    for (int i = 1; i <= N; i++) {
        if (d[i] == K) {
            chk = true;
            cout << i << '\n';
        }
    }
 
    if (!chk) cout << "-1\n";
}
 
void dijkstra() {
    d[start] = 0;
    priority_queue<pair<intint> > q;
    q.push({ start, 0 });
    while (!q.empty()) {
        int now = q.top().first;
        int dis = -q.top().second;
        q.pop();
 
        if (d[now] < dis) continue;
 
        for (int i = 0; i < list[now].size(); i++) {
            int next = list[now][i].first;
            int nextdis = dis + list[now][i].second;
 
            if (d[next] > nextdis) {
                d[next] = nextdis;
                q.push({ next, -nextdis });
            }
        }
    }
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        d[i] = INF;
    }
}
 
void input() {
    int u, v;
    cin >> N >> M >> K >> start;
    init();
 
    while (M--) {
        cin >> u >> v;
        list[u].push_back({ v,1 });
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    dijkstra();
    solve();
 
    return 0;
}
cs

 

 

[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
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
 
vector<int> list[300001];
queue<int> q;
int d[300001];
int N, M, K, start;
 
void solve() {
    bool chk = false;
    for (int i = 1; i <= N; i++) {
        if (d[i] == K) {
            chk = true;
            cout << i << '\n';
        }
    }
 
    if (!chk) cout << "-1\n";
}
 
void bfs() {
    q.push(start);
    d[start] = 0;
    for (int t = 1; t <= K; t++) {
        int qsize = q.size();
        while (qsize--) {
            int x = q.front();
            q.pop();
 
            for (int i = 0; i < list[x].size(); i++) {
                int next = list[x][i];
                if (d[next] != -1continue;
                
                q.push(next);
                d[next] = t;
            }
        }
    }
}
 
void input() {
    int u, v;
    cin >> N >> M >> K >> start;
    while (M--) {
        cin >> u >> v;
        list[u].push_back(v);
    }
    memset(d, -1sizeof(d));
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    bfs();
    solve();
 
    return 0;
}
cs

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

boj 4485 녹색 옷 입은 애가 젤다지?  (0) 2021.03.23
boj 14496 그대, 그머가 되어  (0) 2021.03.22

www.acmicpc.net/problem/14496

 

14496번: 그대, 그머가 되어

첫째 줄에 머호가 바꾸려 하는 문자 a와 b가 주어진다. 둘째 줄에 전체 문자의 수 N과 치환 가능한 문자쌍의 수 M이 주어진다. (1 <= N <= 1,000, 1 <= M <= 10,000) 이후 M개의 줄에 걸쳐 치환 가능한 문자쌍

www.acmicpc.net

a를 b로 바꾸기 위해 필요한 최소 치환 횟수 -> a에서 b로 이동하기 위한 최단 거리

이렇게 바꾸어서 해결할 수 있습니다.

최단거리는 다익스트라를 이용합니다.

 

이 문제는 가중치가 주어지지 않으므로 모든 가중치는 1입니다.

입력으로 인접한 노드 번호 쌍이 주어지고 무방향 그래프입니다.

 

큐를 이용한 다익스트라를 사용하였고,

목적지인 b까지 도달할 수 있으면 d[des] 출력

목적지인 b까지 도달할 수 없으면 -1을 출력합니다.

 

 

다익스트라 기본 개념은 이곳에서 공부하였습니다.

blog.naver.com/PostView.nhn?blogId=ndb796&logNo=221234424646&categoryNo=128&parentCategoryNo=0&viewDate=&currentPage=5&postListTopCurrentPage=&from=postList&userTopListOpen=true&userTopListCount=5&userTopListManageOpen=false&userTopListCurrentPage=5

 

23. 다익스트라(Dijkstra) 알고리즘

다익스트라(Dijkstra) 알고리즘은 다이나믹 프로그래밍을 활용한 대표적인 최단 경로(Shortest Path) 탐...

blog.naver.com

 

 

[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
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#define INF 1000000000
using namespace std;
 
vector<pair<intint> > list[1001];
int d[1001];
int N, M, start, des;
 
void dijkstra() {
    d[start] = 0;
    priority_queue<pair<intint> > q;
    q.push({ start, 0 });
    while (!q.empty()) {
        int x = q.top().first;
        int dis = -q.top().second;
        q.pop();
 
        if (d[x] < dis) continue;
 
        for (int i = 0; i < list[x].size(); i++) {
            int next = list[x][i].first;
            int nextdis = dis + list[x][i].second;
 
            if (d[next] > nextdis) {
                d[next] = nextdis;
                q.push({ next, -nextdis });
            }
        }
    }
    if (d[des] == INF) cout << "-1\n";
    else cout << d[des] << '\n';
}
 
void init() {
    for (int i = 1; i <= N; i++) {
        d[i] = INF;
    }
}
 
void input() {
    int u, v;
    cin >> start >> des >> N >> M;
    init();
 
    while (M--) {
        cin >> u >> v;
        list[u].push_back({ v,1 });
        list[v].push_back({ u,1 });
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    dijkstra();
 
    return 0;
}
cs

 

 

[Java]

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
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    static ArrayList<int[]> list[] = new ArrayList[1001];
    static final int INF = 1000000000;
    static int d[] = new int[1001];
    static int N, M, start, des;
 
    static void dijkstra() {
        PriorityQueue<int[]> q = new PriorityQueue<>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1- o2[1];
            }
        });
 
        q.add(new int[] { start, 0 });
        d[start] = 0;
        while (!q.isEmpty()) {
            int now = q.peek()[0];
            int dis = q.poll()[1];
 
            if (d[now] < dis)
                continue;
 
            for (int i = 0; i < list[now].size(); i++) {
                int next = list[now].get(i)[0];
                int nextdis = dis + list[now].get(i)[1];
 
                if (d[next] > nextdis) {
                    d[next] = nextdis;
                    q.add(new int[] { next, nextdis });
                }
            }
        }
 
        if (d[des] == INF)
            System.out.println(-1);
        else
            System.out.println(d[des]);
    }
 
    static void init() {
        for (int i = 1; i <= N; i++) {
            list[i] = new ArrayList<>();
            d[i] = INF;
        }
    }
 
    static void input() throws Exception {
        int u, v;
        st = new StringTokenizer(br.readLine());
        start = Integer.parseInt(st.nextToken());
        des = Integer.parseInt(st.nextToken());
 
        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        init();
 
        while (M-- > 0) {
            st = new StringTokenizer(br.readLine());
            u = Integer.parseInt(st.nextToken());
            v = Integer.parseInt(st.nextToken());
 
            list[u].add(new int[] { v, 1 });
            list[v].add(new int[] { u, 1 });
        }
    }
 
    public static void main(String[] args) throws Exception {
        input();
        dijkstra();
    }
}
cs

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

boj 4485 녹색 옷 입은 애가 젤다지?  (0) 2021.03.23
boj 18352 특정 거리의 도시 찾기  (0) 2021.03.22

www.acmicpc.net/problem/2228

 

2228번: 구간 나누기

N(1≤N≤100)개의 수로 이루어진 1차원 배열이 있다. 이 배열에서 M(1≤M≤⌈(N/2)⌉)개의 구간을 선택해서, 구간에 속한 수들의 총 합이 최대가 되도록 하려 한다. 단, 다음의 조건들이 만족되어야

www.acmicpc.net

이 문제는 조건을 잘 확인해야 합니다.

1. 각 구간은 한 개 이상의 연속된 수들로 이루어진다.

2. 서로 다른 두 구간끼리 겹쳐있거나 인접해 있어서는 안 된다.

3. 정확히 M개의 구간이 있어야 한다. M개 미만이어서는 안 된다

6 2
-1
3
1
2
4
-1

위 예제에서의 답은 {3}과 {2, 4}를 선택하여 9입니다.

 

dp[idx][cnt] = 구간의 시작인덱스가 idx이고 cnt번째 구간일 때의 최댓값>

idx가 구간의 시작점이고, 구간의 끝은 반복문을 통해 구하였습니다.

 

구간의 끝을 구하기 전에 idx번째 수를 선택하지 않을 수도 있기때문에 먼저 구해주었습니다.

idx ~ i의 구간을 골랐으면 다음 구간은 이 구간과 인접해있으면 안되기때문에 i+2를 넘겨주었습니다.

 

정확히 M개를 골랐으면 합의 최댓값을 갱신, 남은 배열에서 M개의 구간을 못 고르는 경우 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
#include <iostream>
#include <algorithm>
#define INF 1000000000
using namespace std;
 
int list[101], sum[101], dp[101][51];
int N, M;
 
int func(int idx, int cnt) {
    if (cnt == M) return 0;
    if ((N - idx + 2/ 2 < M - cnt) return -INF;
 
    int &ret = dp[idx][cnt];
    if (ret != -INF) return ret;
    ret = func(idx + 1, cnt);
 
    for (int i = idx; i <= N; i++) {
        ret = max(ret, func(i + 2, cnt + 1+ sum[i] - sum[idx - 1]);
    }
 
    return ret;
}
 
void init() {
    for (int i = 0; i <= N; i++) {
        for (int j = 0; j <= M; j++) {
            dp[i][j] = -INF;
        }
    }
}
 
void input() {
    cin >> N >> M;
    for (int i = 1; i <= N; i++) {
        cin >> list[i];
        sum[i] = sum[i - 1+ list[i];
    }
    init();
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    cout << func(10<< '\n';
 
    return 0;
}
cs

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

boj 1937 욕심쟁이 판다  (0) 2021.03.28
boj 2201 이친수 찾기  (2) 2021.03.24
boj 1695 팰린드롬 만들기  (0) 2021.03.20
boj 9177 단어 섞기  (0) 2021.03.19
boj 10942 팰린드롬?  (0) 2021.03.12

www.acmicpc.net/problem/1695

 

1695번: 팰린드롬 만들기

앞에서 뒤로 보나, 뒤에서 앞으로 보나 같은 수열을 팰린드롬 이라고 한다. 예를 들어 {1}, {1, 2, 1}, {1, 2, 2, 1}과 같은 수열은 팰린드롬 이지만, {1, 2, 3}, {1, 2, 3, 2} 등은 팰린드롬이 아니다. 한 수열

www.acmicpc.net

입력으로 주어진 수열에 무작위로 수를 끼워넣어 팰린드롬으로 만드는데 최소 몇개의 수를 끼워 넣으면 되는지 구하는 문제입니다.

 

이 문제는 간단하게 주어진 수열과 뒤집은 수열의 lcs를 구한 후 N에서 뺀 값이 답입니다.

메모리 손해를 보지 않기위해 슬라이딩 윈도우 기법을 사용하였습니다.

 

 

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
#include <iostream>
#define max(a, b) {a > b ? a : b}
using namespace std;
 
int dp[2][5001], list[5001];
int N;
 
void func() {
    int t = 0;
    for (int i = N; i >= 1; i--) {
        for (int j = 1; j <= N; j++) {
            if (list[i] == list[j]) {
                dp[t][j] = dp[1 - t][j - 1+ 1;
            }
            else dp[t][j] = max(dp[1 - t][j], dp[t][j - 1]);
        }
        t = 1 - t;
    }
    
    cout << N - dp[1 - t][N] << '\n';
}
 
void input() {
    cin >> N;
    for (int i = 1; i <= N; i++) {
        cin >> list[i];
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

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

boj 2201 이친수 찾기  (2) 2021.03.24
boj 2228 구간 나누기  (0) 2021.03.21
boj 9177 단어 섞기  (0) 2021.03.19
boj 10942 팰린드롬?  (0) 2021.03.12
boj 17404 RGB거리 2  (0) 2021.02.28

www.acmicpc.net/problem/9177

 

9177번: 단어 섞기

세 개의 단어가 주어졌을때, 꿍은 첫 번째 단어와 두 번째 단어를 섞어서 세 번째 단어를 만들 수 있는지 궁금해졌다. 첫 번째와 두 번째 단어는 마음대로 섞어도 되지만 원래의 순서는 섞여서는

www.acmicpc.net

str1 : 첫 번째 단어

str2 : 두 번째 단어

result : 세 번째 단어

 

dp[idx1][idx2] : 현재 확인하려는 알파벳이 str1[idx1], str2[idx2]일 때 result를 만들 수 있는지 여부

 

재귀를 통해 두 단어와 세 번째 단어를 비교할 인덱스(idx1, idx2, idx)를 넘겨줍니다.

str1[idx1] == result[idx]이면 첫 번째 단어와 세 번째 단어의 인덱스를 1 증가(idx1 + 1, idx2, idx + 1)

str2[idx2] == result[idx]이면 두 번째 단어와 세 번째 단어의 인덱스를 1 증가(idx1, idx2 + 1, idx + 1)

를 확인해줍니다.

 

인덱스의 조합이 중복으로 나오기때문에 시간적 손해를 줄이기위해 dp를 사용하였습니다.

 

 

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
#include <iostream>
#include <string>
#include <cstring>
#define max(a, b) {a > b ? a : b}
using namespace std;
 
string str1, str2, result;
int dp[201][201];
int size1, size2, rsize;
 
int func(int idx1, int idx2, int idx) {
    if (idx == rsize) return 1;
 
    int &ret = dp[idx1][idx2];
 
    if (ret != -1return ret;
    ret = 0;
 
    if (idx1 < size1 && str1[idx1] == result[idx]) ret = func(idx1 + 1, idx2, idx + 1);
    if (idx2 < size2 && str2[idx2] == result[idx]) ret = max(ret, func(idx1, idx2 + 1, idx + 1));
 
    return ret;
}
 
void input() {
    cin >> str1 >> str2 >> result;
    size1 = str1.size();
    size2 = str2.size();
    rsize = result.size();
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    int tc;
    cin >> tc;
    for (int t = 1; t <= tc; t++) {
        memset(dp, -1sizeof(dp));
        cout << "Data set " << t << ": ";
        input();
        if (func(000)) cout << "yes\n";
        else cout << "no\n";
    }
 
 
    return 0;
}
cs

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

boj 2228 구간 나누기  (0) 2021.03.21
boj 1695 팰린드롬 만들기  (0) 2021.03.20
boj 10942 팰린드롬?  (0) 2021.03.12
boj 17404 RGB거리 2  (0) 2021.02.28
boj 2616 소형기관차  (0) 2021.02.27

+ Recent posts