www.acmicpc.net/problem/15686

 

15686번: 치킨 배달

크기가 N×N인 도시가 있다. 도시는 1×1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸

www.acmicpc.net

 

생각보다 쉽게 풀었다. 치킨집이 총 13개까지 주어지는 조건을 봤고,

치킨집과 집을 매칭 시키는 것이 combination을 떠올리게 한다.

따라서 그래프 탐색이 아니라 조합, 경우의 수로 접근해봤다.

 

일단 보자마자 집을 원소로 가지는 a벡터, 치킨집을 원소로 가지는 b벡터를 인자로

받아 각 원소를 \(O(N^2)\)으로 순회하며 가장 작은 치킨 거리를 찾아 리턴해주는 함수를 만들었다.

 

 

1
2
3
4
5
6
7
8
9
10
11
int all(vector<pair<intint>>& a, vector<pair<intint>>& b) {
    int ret = 0;
    for (auto i : a) {
        int tmp = 1e9;
        for (auto j : b) {
            tmp = min(tmp, abs(i.first - j.first) + abs(i.second - j.second));
        }
        ret += tmp;
    }
    return ret;
}
cs

 

이건 쉽게 구현 가능하고 이제 치킨집에서 총 M개의 원소를 뽑아서 각각 a, b를 매칭 시켜주면 된다.

처음에는 next_permutation을 이용한 순열로 접근했지만 모든 경우의 수를 따지면 시간초과가 난다.

 

 

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
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
 
    int n, m, ans = 1e9;
    vector<pair<intint>> a, b;
 
    cin >> n >> m;
    for (int i=0;i<n;++i)
        for (int j = 0; j < n; ++j) {
            int x; cin >> x;
            if (x == 1) a.push_back({ i,j });
            else if (x == 2) b.push_back({ i,j });
        }
 
    do {
        vector<pair<intint>> go;
        for (int i = 0; i < m; ++i)
            go.push_back(b[i]);
        ans = min(ans, all(a, go));
    } while (next_permutation(b.begin(), b.end()));
 
    cout << ans << endl;
 
    return 0;
}
cs

 

 

그래서 지우고 조합으로 다시 접근해줬는데 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
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
    
int n, m, ans = 1e9;
vector<pair<intint>> a, b, tmp(13);
bool vis[13];
 
int all(vector<pair<intint>>& a, vector<pair<intint>>& b) {
    int ret = 0;
    for (auto i : a) {
        int tmp = 1e9;
        for (auto j : b) {
            tmp = min(tmp, abs(i.first - j.first) + abs(i.second - j.second));
        }
        ret += tmp;
    }
    return ret;
}
 
void dfs(int cnt, int idx) {
    if (cnt == m) {
        vector<pair<intint>> go;
        for (int i = 0; i < m; ++i) go.push_back(tmp[i]);
        ans = min(ans, all(a, go));
        return;
    }
    for (int i = idx; i < b.size(); ++i) {
        if (!vis[i]) {
            vis[i] = true;
            tmp[cnt] = b[i];
            dfs(cnt + 1, i);
            vis[i] = false;
        }
    }
}
 
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
 
    cin >> n >> m;
    for (int i=0;i<n;++i)
        for (int j = 0; j < n; ++j) {
            int x; cin >> x;
            if (x == 1) a.push_back({ i,j });
            else if (x == 2) b.push_back({ i,j });
        }
 
    dfs(00);
 
    cout << ans << endl;
 
    return 0;
}
cs

 

'BOJ' 카테고리의 다른 글

BOJ 13549 숨바꼭질 3  (0) 2020.12.28
BOJ 12851 숨바꼭질 2  (0) 2020.12.28
BOJ 3190 뱀  (0) 2020.12.19
BOJ 1446 지름길  (0) 2020.12.16
BOJ 1915 가장 큰 정사각형  (0) 2020.12.13

www.acmicpc.net/problem/3190

 

3190번: 뱀

 'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다. 게임

www.acmicpc.net

 

뱀은 매 초마다 이동을 하는데 다음과 같은 규칙을 따른다.

  • 먼저 뱀은 몸길이를 늘려 머리를 다음칸에 위치시킨다.
  • 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.
  • 만약 이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸길이는 변하지 않는다.

deque를 사용하면 앞뒤로 삽입과 삭제를 용이하게 할 수 있다.

일단 방향을 정해주는데 북, 동, 서, 남을 차례로 0, 1, 2, 3으로 설정해준다.

이러면 dx, dy해주는 부분은

 

int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 };

 

가 되고, 방향을 조절해주는 함수는 다음과 같이 쉽게 작성할 수 있다.

 

void dir(char C) {
	if (C == 'L') !d ? d = 3 : d--;
	else d == 3 ? d = 0 : d++;
}

 

처음에는 X와 C가 주어지면 X만큼 이동 후 C방향으로 회전시키는 것인 줄 알았는데

X가 현재 초를 가르키는 거라 고생 좀 했다.

 

우선 뱀이 움직이는 부분은 쉽게 구현 가능하다.

아무것도 아닌 부분은 '.', 뱀이 위치하고 있는 부분은 'o', 사과가 존재하는 부분은 '*'로 놓고

 

 

1
2
3
4
5
6
7
8
9
10
if (a[nx][ny] == '.') { //이동하려는 곳이 아무것도 아니라면
    dq.push_front({ nx,ny }); //덱에 넣어주고
    a[nx][ny] = 'o'//o로 바꿔준다
    a[dq.back().first][dq.back().second] = '.'//꼬리 부분은 다
    dq.pop_back();
}
else if (a[nx][ny] == '*') { //사과가 존재하면
    dq.push_front({ nx,ny });
    a[nx][ny] = 'o'//꼬리는 떼지 않는다.
}
cs

 

위처럼 구현하고 dir함수를 통해 방향을 바꿔준다.

 

이제 남은 구현부분은 이미 충돌했거나, 범위 밖을 벗어나는 경우 더 이상 X와 C를 받지 않고

빠져나와야 하는데 나는 뱀이 이동하는 bfs 함수를 boolean으로 작성하여 해결했다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    bool go = true;
    for (int i = 0; i < l; ++i) {
        int x; char c; cin >> x >> c;
        go = query(x, c);
        if (!go) break;
    }
 
    if (!go) cout << t << endl;
    else {
        while (dq.front().first >= 0 && dq.front().first < n && dq.front().second >= 0 && dq.front().second < n) {
            ++t;
            if (a[dq.front().first+dx[d]][dq.front().second+dy[d]] == 'o'break;
            dq.push_front({ dq.front().first + dx[d],dq.front().second + dy[d] });
        }
        cout << t-1 << endl;
    }
cs

 

만약 중간에 반복문을 빠져나온게 아니라 query를 전부 수행했다면

이제 벽에 박을 때까지 진행시켜주면 된다.

 

최종 코드

 

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
#include <iostream>
#include <deque>
using namespace std;
 
int n, k, l, d, t = 1;
char a[101][101];
deque<pair<intint>> dq;
int dx[4= { -1,0,1,0 };
int dy[4= { 0,1,0,-1 };
 
void dir(char C) {
    if (C == 'L'!d ? d = 3 : d--;
    else d == 3 ? d = 0 : d++;
}
 
bool query(int x, char c) {
    for (; t <= x; ++t) {
        int nx = dq.front().first + dx[d];
        int ny = dq.front().second + dy[d];
        if (nx < 0 || nx >= n || ny < 0 || ny >= n) return false;
        if (a[nx][ny] == '.') {
            dq.push_front({ nx,ny });
            a[nx][ny] = 'o';
            a[dq.back().first][dq.back().second] = '.';
            dq.pop_back();
        }
        else if (a[nx][ny] == '*') { 
            dq.push_front({ nx,ny });
            a[nx][ny] = 'o';
        }
        else if (a[nx][ny] == 'o'return false;
    }
    dir(c);
    return true;
}
 
int main() {
    cin >> n >> k;
    for (int i = 0; i <= n; ++i)
        for (int j = 0; j <= n; ++j)
            a[i][j] = '.';
 
    for (int i = 0; i < k; ++i) {
        int x, y; cin >> x >> y;
        a[x - 1][y - 1= '*';
    }
    a[0][0= 'o';
    dq.push_back({ 0,0 });
    d = 1
    
    cin >> l;
    bool go = true;
    for (int i = 0; i < l; ++i) {
        int x; char c; cin >> x >> c;
        go = query(x, c);
        if (!go) break;
    }
 
    if (!go) cout << t << endl;
    else {
        while (dq.front().first >= 0 && dq.front().first < n && dq.front().second >= 0 && dq.front().second < n) {
            ++t;
            if (a[dq.front().first+dx[d]][dq.front().second+dy[d]] == 'o'break;
            dq.push_front({ dq.front().first + dx[d],dq.front().second + dy[d] });
        }
        cout << t-1 << endl;
    }
 
    return 0;
}
cs

'BOJ' 카테고리의 다른 글

BOJ 12851 숨바꼭질 2  (0) 2020.12.28
BOJ 15686 치킨 배달  (0) 2020.12.25
BOJ 1446 지름길  (0) 2020.12.16
BOJ 1915 가장 큰 정사각형  (0) 2020.12.13
BOJ 7579 앱  (0) 2020.12.13

www.acmicpc.net/problem/1446

 

1446번: 지름길

첫째 줄에 지름길의 개수 N과 고속도로의 길이 D가 주어진다. N은 12 이하이고, D는 10,000보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 지름길의 시작 위치, 도착 위치, 지름길의 길이가 주

www.acmicpc.net

 

문제는 그리디 하게 접근해야 한다는 것이다. 그냥 지름길이 주어졌다고 해서 지금 길만 탄다면

다른 컴포넌트에 있는 길로 가는 것이 더 빠를 수 있다.

 

어떻게 접근해야 할까?

 

핵심은 다익스트라를 돌리면서 현재 위치 + 1 에 지름길이 없다면 우선순위 큐에 

cost + 1 로 넣어주는 것이다.

 

이렇게 되면 자연히 d 이하의 모든 노드를 탐색하면서 지름길이 있다면 지름길을 타고, 아니라면

다음 컴포넌트가 큐에 들어가게 된다.

 

 

1
2
3
4
if (cur + 1 <= k && d[cur + 1] > cost + 1) {
    d[cur + 1] = cost + 1;
    q.push({ -(cost + 1),cur + 1 });
}
cs

 

k 가 고속도로의 길이 d라고 하면 현재 위치 cur + 1 이 k보다 작아야 하고(고속도로를 역주행할 수는 없기 때문에)

그다음 위치가 현 비용 + 1 보다 크다면(INF라면) 

다른 컴포넌트이기 때문에 그 위치를 큐에 넣어줘야 한다.

 

 

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>
#include <vector>
#include <queue>
using namespace std;
 
vector<pair<intint>> a[10001];
priority_queue<pair<intint>> q;
const int inf = 1e9;
int n, k;
 
int dijkstra(int s, int e) {
    vector<int> d(10001, inf);
    q.push({ 0,s });
    d[s] = 0;
 
    while (!q.empty()) {
        auto cur = q.top().second;
        int cost = -q.top().first;
        q.pop();
        if (d[cur] < cost) continue;
        for (auto i : a[cur]) {
            int nc = cost + i.second;
            if (nc < d[i.first]) {
                d[i.first] = nc;
                q.push({ -nc,i.first });
            }
        }
        if (cur + 1 <= k && d[cur + 1> cost + 1) {
            d[cur + 1= cost + 1;
            q.push({ -(cost + 1),cur + 1 });
        }
    }
    return d[e];
}
 
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
 
    cin >> n >> k;
    for (int i = 0; i < n; ++i) {
        int x, y, z; cin >> x >> y >> z;
        a[x].push_back({ y,z });
    }
 
    cout << dijkstra(0, k) << endl;
 
    return 0;
}
cs

 

 

'BOJ' 카테고리의 다른 글

BOJ 15686 치킨 배달  (0) 2020.12.25
BOJ 3190 뱀  (0) 2020.12.19
BOJ 1915 가장 큰 정사각형  (0) 2020.12.13
BOJ 7579 앱  (0) 2020.12.13
BOJ 5052 전화번호 목록  (0) 2020.12.10

+ Recent posts