BOJ 3190 뱀

대학교 동기들이 물어봐서 다시 한 번 풀어봤습니다.

문제에서 요구하는데로 그대로 따라하면 해결할 수 있습니다.

저는 map에서 0은 빈 공간, 1은 뱀을 나타내는 값, 2는 사과를 저장합니다.

turnInfo에는 문제에서 주어지는 L의 값들을 구조체로 저장했습니다.

나머지는 주석을 달아놓았습니다.

궁금한 점은 댓글달아주세요^^

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
#include <iostream>
#include <queue>
 
#define MAX_SIZE 100
#define mp make_pair
 
using namespace std;
 
typedef pair<intint> pii;
typedef struct {
    int sec;
    int dir;
}TurnInfo;
 
 
int n; //보드 크기
int map[MAX_SIZE][MAX_SIZE]; // 사과는 2, 뱀은 1, 맵은 0
TurnInfo turnInfo[MAX_SIZE];
int dx[4= { -1100 };
int dy[4= { 00-11 };
 
//오른쪽 : 위 -> 오, 아래 -> 왼, 오 -> 아, 왼 -> 위
//왼쪽 : 위 -> 왼, 아래 -> 오른, 오 -> 위, 왼 -> 아
 
//r : 0 -> 3, 1 -> 2, 3 -> 1, 2 -> 0
//l : 0 -> 2, 1 -> 3, 3 -> 0, 2 -> 1
 
int turn(int now, int next)
{
    if (next == 0// 왼쪽
    {
        if (now == 0 || now == 1return (now + 2) % 4;
        else return 3 - now;
    }
    else // 오른쪽
    {
        if (now == 0 || now == 1return 3 - now;
        else return (now + 2) % 4;
    }
}
 
bool isDead(pii headPos) {
    //벽을 박았는지
    if (headPos.first < 0 || headPos.second < 0 || headPos.first >= n || headPos.second >= n) {
        return 1;
    }
    //내 몸을 부딪혔는지?
    else if (map[headPos.first][headPos.second] == 1) {
        return 1;
    }
 
    //위에 속하지 않으면 살았다.
    return 0;
}
 
int main() {
    cin >> n;
 
    //사과 개수
    int k;
    cin >> k;
 
    //사과를 2로 맵에 표시
    for (int i = 0; i < k; i++) {
        int x, y;
        cin >> x >> y;
        map[x - 1][y - 1= 2;
    }
 
 
    //방향 변환 개수
    int l;
    cin >> l;
 
    //방향 변환 x는 시간 c는 방향
    for (int i = 0; i < l; i++) {
        int x;
        char c;
        cin >> x >> c;
 
        turnInfo[i].sec = x;
 
        if (c == 'L') {
            turnInfo[i].dir = 0;
        }
        else {
            turnInfo[i].dir = 1;
        }
    }
 
    //위에까지 인풋
    
    queue<pii> snakeTrace; // 뱀 자취
    int sec = 0// 현재 시간은 0
    int snakeDir = 3// 초기 방향 오른쪽
 
    pii headPos;//머리 위치
    headPos.first = headPos.second = 0// 뱀 머리 위치 0, 0으로
 
    //turnInfo 인덱스
    int turnInfoIdx = 0;
 
    //뱀이 죽지않으면 루프
    while (!isDead(headPos)) {
        //현재시간이 0이 아닌데 map이 0이면 꼬리가 잘려야함
        //맵은 0이면 빈공간, 1이면 뱀의 몸, 2이면 사과
        //sec != 0 이 조건은 시작점은 무조건 map이 0이기 때문에 시작하자마자 꼬리가 잘릴 순 없음
        if (sec != 0 && map[headPos.first][headPos.second] == 0) {    
            map[snakeTrace.front().first][snakeTrace.front().second] = 0;//꼬리의 map을 빈공간으로 만들어줌 즉, 잘라버림
            snakeTrace.pop();//내 몸을 보관하고 있는 큐에서 꼬리를 버림
        }
 
        //머리가 위치한 곳의 맵을 1로만들어줌
        map[headPos.first][headPos.second] = 1;
        snakeTrace.push(headPos);//뱀의 머리를 넣기
 
        //turnInfoIdx가 입력받은 l보다 작아야함 같거나 크다면 방향을 전환할 곳이 없으므로 가던곳으로 가야함
        if (turnInfoIdx < l) {
            if (sec == turnInfo[turnInfoIdx].sec) {//현재시간과 방향전환해야하는 시간이 같으면
                snakeDir = turn(snakeDir, turnInfo[turnInfoIdx].dir);//뱀의 방향을 전환해줌
                turnInfoIdx++;//턴정보 인덱스 증가
            }
        }
 
        //뱀의 머리를 다음 위치로 이동시킴
        headPos.first += dx[snakeDir];
        headPos.second += dy[snakeDir];
        sec++;    //시간증가
    }
 
    cout << sec;
 
    return 0;
}
cs


'알고리즘 > 구현' 카테고리의 다른 글

[2140] 지뢰찾기  (0) 2017.12.27
[12845] 모두의 마블  (0) 2017.08.26
[12841] 정보대 등산  (0) 2017.08.23
[1700] 멀티탭 스케줄링  (0) 2017.08.01
[1992] 쿼드 트리  (0) 2017.07.30

BOJ 2140 지뢰찾기

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

단순하게 구현하면 되는 문제입니다.

맵의 크기가 n이라고 가정했을 때,

테두리 옆의 # 즉 숫자 옆의 #들만 신경쓰면 됩니다.

그 외의 #들은 지뢰가 있을 수도 있고 없을 수도 있지만, 저희는 다 있다고 가정하고 풀어야합니다.

문제에서 요구하는 것이 최댓값이기 때문입니다.

테두리 옆의 #들은 8방향으로 검사를 해서 만약 주변의 숫자 중에 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
#include <iostream>
#include <queue>
 
using namespace std;
 
char map[100][105];
int dx[8= { 10-10-111-1 };
int dy[8= { 010-111-1-1 };
int n;
 
bool check(int x, int y) {
    for (int i = 0; i < 8; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];
 
        if (nx < 0 || ny < 0 || nx >= n || ny >= n) {
            continue;
        }
 
        if (map[nx][ny] == '0'return 0;
    }
 
    return 1;
}
 
void doMinus(int x, int y) {
    for (int i = 0; i < 8; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];
 
        if (nx < 0 || ny < 0 || nx >= n || ny >= n) {
            continue;
        }
 
        if (map[nx][ny] >= '0' && map[nx][ny] <= '9') map[nx][ny]--;
    }
}
 
int main() {
    cin >> n;
 
    if (n <= 2) {
        cout << 0;
        return 0;
    }
 
    int ret = (n - 2* (n - 2);
 
    for (int i = 0; i < n; i++cin >> map[i];
 
    for (int i = 1; i < n - 1; i++) {
        for (int j = 1; j < n - 1; j++) {
            if (i == 1 || j == 1 || i == n - 2 || j == n - 2) {
                if (check(i, j)) {
                    doMinus(i, j);
                }
                else {
                    ret--;
                }
            }
        }
    }
 
    cout << ret;
 
    return 0;
}
cs


'알고리즘 > 구현' 카테고리의 다른 글

[3190] 뱀  (4) 2018.01.10
[12845] 모두의 마블  (0) 2017.08.26
[12841] 정보대 등산  (0) 2017.08.23
[1700] 멀티탭 스케줄링  (0) 2017.08.01
[1992] 쿼드 트리  (0) 2017.07.30

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


LIS 문제입니다.

꼬이지 않으려면 내가 연결한 전봇대 보다 번호가 더 큰 전봇대만 선택해야하기 때문입니다.

N^2의 방법으로 해결하려고 했으나,  N이 너무 큽니다.


NlogN으로 해결하는 Lower Bound LIS로 해결해야합니다.

저도 처음해봤는데..


우선 로워바운드는 해당 숫자 이상의 수 중에서 가장 가까운 인덱스를 리턴하는 함수입니다.

(정렬이 되어있을 떄만 가능합니다. 이분 탐색을 응용한 것이기 떄문입니다.)


a배열은 입력들어오는 배열이고

b배열은 정렬된 수가 들어가 있는 배열입니다.

주의할 점은 b배열이 lis의 부분수열이 들어가있는 배열이 아니라는 점입니다.


로워 바운드는 자기보다 작거나 같은 경우 b배열에서 수행해서 자기의 위치를 찾아서 대입합니다.


예를 들어 10 20 30 1 2 3 4 5

라는 수열이 있으면


b배열에 10 20 30 이렇게 들어갈 것입니다.

허나 1을 만나면 10 20 30 이 들어있는 수열에서

로워바운드를 하여 자기 이상의 수 중 가장 인덱스를 찾겠죠.

네 value:10, idx:0 입니다.

그러면 b 배열은 1 20 30으로 바뀌게 됩니다.


또 2를 만나면 자기보다 큰 수를 찾겠죠. 네 20입니다.

1 2 30 으로 바뀌게 됩니다.


3을 만나면

1 2 3으로 바뀌겠죠.

4와 5는 b배열의 3보다 크므로 그냥 삽입하면 됩니다.


b배열은 1 2 3 4 5가 완성이 됩니다.

결국 lis값은 5가 되겠죠.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
 
using namespace std;
int a[(int)1e5];
int b[(int)1e5];
 
int lower_bound(int s, int e, int value) {
    
    while (s <= e) {
        int mid = (s + e) / 2;
 
        if (b[mid] >= value) e = mid - 1;
        else s = mid + 1;
    }
 
    return s;
}
 
int main() {
    int n;
    scanf("%d"&n);
 
    for (int i = 0; i < n; i++) {
        scanf("%d"&a[i]);
    }
        
    int size = 1;
    b[0= a[0];
    
    for (int i = 1; i < n; i++) {
        if (b[size - 1< a[i]) {
            b[size= a[i];
            size++;
            continue;
        }
 
        b[lower_bound(0size - 1, a[i])] = a[i];
    }
    
    printf("%d", n - size);
 
    return 0;
}
cs


'알고리즘 > 다이나믹 프로그래밍(DP)' 카테고리의 다른 글

[1890] 점프  (0) 2017.09.15
[2565] 전깃줄  (0) 2017.09.07
[2688] 줄어들지 않아  (0) 2017.07.27
[12026] BOJ 거리  (0) 2017.07.24
[1563] 개근상  (0) 2017.07.24

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


가장 쉬운 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
#include <stdio.h>
 
const int QUEUE_SIZE = 100 * 100 * 4;
 
typedef struct qs {
    int x, y, b;
}qs;
 
 
typedef struct queue {
    qs data[QUEUE_SIZE];
    int front, rear;
 
    queue() {
        front = rear = 0;
    }
 
    int empty() {
        return front == rear;
    }
 
    void push(qs d) {
        rear = (rear + 1) % QUEUE_SIZE;
        data[rear] = d;
    }
 
    qs pop() {
        front = (front + 1) % QUEUE_SIZE;
        return data[front];
    }
}queue;
 
 
int dx[4= { 10-10 };
int dy[4= { 0-101 };
char map[100][100];
int visit[100][100];
 
int main() {
    int m, n;
    scanf("%d %d"&m, &n);
 
    getchar();
 
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            map[i][j] = getchar();
        }
        getchar();
    }
 
    queue q;
    q.push(qs{001});
    visit[0][0= 1;
    
    while (!q.empty()) {
        qs front = q.pop();
 
        if (front.x == m - 1 && front.y == n - 1) {
            printf("%d"front.b);
            break;
        }
 
        for (int i = 0; i < 4; i++) {
            int nx = front.x + dx[i];
            int ny = front.y + dy[i];
 
            if (nx < 0 || ny < 0 || nx >= m || ny >= n || visit[nx][ny]) continue;
            if (map[nx][ny] == '0'continue;
 
            visit[nx][ny] = 1;
            q.push(qs{ nx, ny, front.b + 1 });
        }
 
    }
 
    return 0;
}
cs


'알고리즘 > 탐색' 카테고리의 다른 글

[2667] 단지번호붙이기  (0) 2017.09.15
[10216] Count Circle Groups  (0) 2017.08.10
[10451] 순열 사이클  (0) 2017.07.27
[10974] 모든 순열  (2) 2017.07.27
[1058] 친구  (0) 2017.07.20

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


이 문제는 어렵지 않았습니다.

dp라고 알 수 있는 부분은 이 문제가 경우의 수이고, 정답이 2^63이라면 DP를 제외하고는 시간안에 풀 수 없습니다.


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>
 
using namespace std;
 
typedef long long ll;
 
int dx[] = { 10 };
int dy[] = { 01 };
 
int map[100][100];
ll dp[100][100];
 
int n;
 
ll f(int x, int y) {
    if (x == n - 1 && y == n - 1) {
        return 1;
    }
 
    ll &ret = dp[x][y];
    if (ret != -1return ret;
    ret = 0;
 
    for (int i = 0; i < 2; i++) {
        int nx = x + dx[i] * map[x][y];
        int ny = y + dy[i] * map[x][y];
        if (nx >= n || ny >= n) continue;
 
        ret += f(nx, ny);
    }
 
    return ret;
}
 
int main() {
    cin >> n;
 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> map[i][j];
            dp[i][j] = -1;
        }
    }
 
    cout << f(00);
 
    return 0;
}
cs


'알고리즘 > 다이나믹 프로그래밍(DP)' 카테고리의 다른 글

[1365] 꼬인 전깃줄  (0) 2017.09.16
[2565] 전깃줄  (0) 2017.09.07
[2688] 줄어들지 않아  (0) 2017.07.27
[12026] BOJ 거리  (0) 2017.07.24
[1563] 개근상  (0) 2017.07.24

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


STL을 자꾸 쓰니까 실력이 줄어드는 것 같아서..

STL없이 구현해보려고 노력하고 있습니다.


동서남북으로 연결된 지역은 같은 단지로 취급합니다.

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <string>
 
using namespace std;
 
string map[25];
bool visit[25][25];
 
int dx[4= { 10-10 };
int dy[4= { 010-1 };
int n;
 
int max(int a, int b) {
    return a > b ? a : b;
}
 
int dfs(int x, int y) {
    if (visit[x][y]) return 0;
    visit[x][y] = 1;
 
    int ret = 1;
 
    for (int i = 0; i < 4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];
 
        if (nx < 0 || ny < 0 || nx >= n || ny >= n || map[nx][ny] == '0'continue;
        ret += dfs(nx, ny);
    }
 
    return ret;
}
 
void sort(int *arr, int sizeint value) {
    int i = size - 1;
    while (i >= 0 && arr[i] > value) {
        arr[i + 1= arr[i];
        i--;
    }
 
    arr[++i] = value;
}
 
int main() {
    cin >> n;
 
    for (int i = 0; i < n; i++) {
        cin >> map[i];
    }
 
    int ret = 0;
    int cnt[25 * 25];
 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (map[i][j] == '0'continue;
 
            int tmp = dfs(i, j);
            if (tmp) {
                sort(cnt, ret, tmp);
                ret++;
            }
        }
    }
 
    cout << ret<<'\n';
 
    for (int i = 0; i < ret; i++) {
        cout << cnt[i] << '\n';
    }
 
    return 0;
}
cs


'알고리즘 > 탐색' 카테고리의 다른 글

[2178] 미로 탐색  (0) 2017.09.15
[10216] Count Circle Groups  (0) 2017.08.10
[10451] 순열 사이클  (0) 2017.07.27
[10974] 모든 순열  (2) 2017.07.27
[1058] 친구  (0) 2017.07.20

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


입력 받은 N의 쌍을 먼저 만듭니다.


ex) N = 30 이라면.. (1, 30) ... (30, 1) 까지의 쌍이 있겠죠

하지만 (1, 30) (30, 1)은 같은 쌍이고, (2, 15), (15, 2)는 같은 쌍입니다.


그렇기 때문에 sqrt(N)까지만 쌍을 만들면 해결할 수 있습니다.


여기서 주의할 것은 약수라고 무조건 카운트하면 안됩니다.

두 쌍의 최대공약수가 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
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <string.h>
#include <stack>
#include <cstdio>
 
#define mp make_pair
#define MOD 1000000007
#define INF 0x7fffffff
#define MAX_SIZE (int)1e5
 
using namespace std;
//ios::sync_with_stdio(false); cin.tie(0);
 
typedef long long ll;
typedef pair<intint> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<pii> vii;
typedef vector<pll> vll;
typedef vector<bool> vb;
 
int get_gcd(int a, int b) {
    return b ? get_gcd(b, a % b) : a;
}
 
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int test;
    cin >> test;
 
    while (test--) {
        int n;
        cin >> n;
 
        int ret = 0;
 
        for (int i = 1; i * i <= n; i++) {
            if (n % i == 0 && get_gcd(i, n / i) == 1) {
                ret++;
            }
        }
 
        cout << ret << '\n';
    }
    return 0;
}
cs


'알고리즘 > 수학' 카테고리의 다른 글

[2436] 공약수  (2) 2017.09.01
[1740] 거듭 제곱  (0) 2017.06.21

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


LIS문제라는 것을 눈치채지 못한 저는 바보입니다.


LIS입니다..


전형적인 DP문제죠...


dp[n] : 인덱스 n까지의 최대 연결 수


라고 정의하면 됩니다.


이렇게 하면 N^2의 시간복잡도로 해결할 수 있습니다.


관련 문제..

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

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


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
#include <iostream>
#include <vector>
#include <queue>
#include <cmath>
#include <string.h>
#include <stack>
#include <cstdio>
 
#define mp make_pair
#define MOD 1000000007
#define INF 0x7fffffff
#define MAX_SIZE (int)1e5
 
using namespace std;
//ios::sync_with_stdio(false); cin.tie(0);
 
typedef long long ll;
typedef pair<intint> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<pii> vii;
typedef vector<pll> vll;
typedef vector<bool> vb;
 
int edge[501];
int dp[501];
 
int main() {
    int n;
    cin >> n;
 
    for (int i = 0; i < n; i++) {
        int a, b;
        cin >> a >> b;
 
        edge[a] = b;
    }
 
    int ret = 0;
 
    for (int i = 1; i <= 500; i++) {
        if (edge[i] == 0continue;
 
        dp[i] = 1;
 
        for (int j = 1; j < i; j++) {
            if (edge[j] < edge[i]) {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
 
        ret = max(ret, dp[i]);
    }
    
    cout << n - ret;
 
    return 0;
}
cs


'알고리즘 > 다이나믹 프로그래밍(DP)' 카테고리의 다른 글

[1365] 꼬인 전깃줄  (0) 2017.09.16
[1890] 점프  (0) 2017.09.15
[2688] 줄어들지 않아  (0) 2017.07.27
[12026] BOJ 거리  (0) 2017.07.24
[1563] 개근상  (0) 2017.07.24

+ Recent posts