2022.07.04 ㅠㅠ

 

www.acmicpc.net/problem/1713

 

1713번: 후보 추천하기

첫째 줄에는 사진틀의 개수 N이 주어진다. (1≤N≤20) 둘째 줄에는 전체 학생의 총 추천 횟수가 주어지고, 셋째 줄에는 추천받은 학생을 나타내는 번호가 빈 칸을 사이에 두고 추천받은 순서대로

www.acmicpc.net

 

구현, 시뮬레이션 문제

 

  1. 학생들이 추천을 시작하기 전에 모든 사진틀은 비어있다.
  2. 어떤 학생이 특정 학생을 추천하면, 추천받은 학생의 사진이 반드시 사진틀에 게시되어야 한다.
  3. 비어있는 사진틀이 없는 경우에는 현재까지 추천 받은 횟수가 가장 적은 학생의 사진을 삭제하고, 그 자리에 새롭게 추천받은 학생의 사진을 게시한다. 이때, 현재까지 추천 받은 횟수가 가장 적은 학생이 두 명 이상일 경우에는 그러한 학생들 중 게시된 지 가장 오래된 사진을 삭제한다.
  4. 현재 사진이 게시된 학생이 다른 학생의 추천을 받은 경우에는 추천받은 횟수만 증가시킨다.
  5. 사진틀에 게시된 사진이 삭제되는 경우에는 해당 학생이 추천받은 횟수는 0으로 바뀐다.

N이 주어지면 N칸만큼 사진이 게시되어야 하는데 문제를 이해하기에 어려운 내용은 아니다.

구현에 있어서 살짝 까다로운 부분이 있다면 3번이다.

 

우선 나는 풀이를 구현하는데 있어 vector<pair<int,int>> 를 선언해주고

number와 몇 번 불렸는지 cnt로 사용했다.

 

우선 벡터에 push_back으로 추가되니 추천 받은 횟수가 가장 적은 학생이 두명 이상일 경우 앞에 있는 것을 지워주면

되는데 이것은 erase 메소드로 쉽게 처리할 수 있다.

 

또한 C++에는 <algorithm> 헤더 파일에 min_element() 가 존재하는데 람다 함수를 이용해서

pair<> 로 접근하는 것들에 대해서 쉽게 처리해줄 수 있다.

 

min_element(a.begin(), a.end(), [](const auto& lhs, const auto& rhs) {
			return lhs.second < rhs.second;
			})

 

이런 식으로 사용해주면 second가 가장 작은 원소를 찾아 그 iterator를 반환해준다.

 

전체 소스 코드

 

 

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
#include <bits/stdc++.h>
using namespace std;
 
int n, m, x;
vector<pair<intint>> a;
const int inf = 1e9;
 
inline bool f(int key) {
    for (auto& i : a)
        if (i.first == key) {
            ++i.second; return true;
        }
    return false;
}
 
void add(int x) {
    if (a.size() < n) a.push_back({ x,1 }); 
    else { 
        a.erase(min_element(a.begin(), a.end(), [](const auto& lhs, const auto& rhs) {
            return lhs.second < rhs.second;
            }));
        a.push_back({ x,1 });
    }
}
 
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
 
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        cin >> x;
        if (!f(x)) add(x);
    }
 
    sort(a.begin(), a.end());
    for (auto i : a) cout << i.first << ' 'cout << endl;
 
    return 0;
}
cs

 

'BOJ' 카테고리의 다른 글

BOJ 13913 숨바꼭질 4  (0) 2020.12.28
BOJ 13549 숨바꼭질 3  (0) 2020.12.28
BOJ 12851 숨바꼭질 2  (0) 2020.12.28
BOJ 15686 치킨 배달  (0) 2020.12.25
BOJ 3190 뱀  (0) 2020.12.19

www.acmicpc.net/problem/13913

 

13913번: 숨바꼭질 4

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

 

이번 문제는 경로를 추적해서 출력하는 문제였다.

조금만 생각해보면 금방 알 수 있는데, 현재 위치를 지나가는 배열 a를 만들어서

a[next] = cur 를 담고있다고 가정해보면 a[k] 에는 k에 도착하기 전 가장 마지막 위치가 담겨있을 것이고,

a[마지막 위치] 에는 그 위치에 오기 위한 위치가 점진적으로 들어있을 것이다.

 

그렇다면 구현은 간단하다.

기존 bfs를 통해 최단시간을 구할 때 a[next] = cur 만 추가해주고 이후에 재귀적인 호출을 통해

역추적해주면 된다.

 

 

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
#include <iostream>
#include <queue>
using namespace std;
 
int a[100001], n, k;
int vis[100001];
queue<int> q;
 
void backtrace(int cur) {
    if (cur == n) {
        cout << n << ' 'return;
    }
    backtrace(a[cur]);
    cout << cur << ' ';
}
 
int main() {
    cin >> n >> k;
 
    q.push(n);
 
    while (!q.empty()) {
        int cur = q.front(); q.pop();
        if (cur == k) break;
        for (int i : {cur - 1, cur + 1, cur * 2}) {
            if (0 <= i && i <= 100000 && !vis[i]) {
                vis[i] = vis[cur] + 1;
                q.push(i);
                a[i] = cur;
            }
        }
    }
 
    cout << vis[k] << endl;
    backtrace(k);
    cout << endl;
 
    return 0;
}
cs

 

'BOJ' 카테고리의 다른 글

BOJ 1713 후보 추천하기  (0) 2021.01.01
BOJ 13549 숨바꼭질 3  (0) 2020.12.28
BOJ 12851 숨바꼭질 2  (0) 2020.12.28
BOJ 15686 치킨 배달  (0) 2020.12.25
BOJ 3190 뱀  (0) 2020.12.19

www.acmicpc.net/problem/13549

 

13549번: 숨바꼭질 3

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net

 

숨바꼭질 2와 다르게 3은 cur * 2 지점으로 텔레포트할 때에 시간이 소요되지 않는다.

평범하게 큐로 bfs 할 경우 기존 cur -1, cur + 1을 하면서 K에 도착하게 되면

이후에 cur * 2 를 통해 도착하는 시간보다 더 크지만 이미 방문처리가 되어있으므로 값을

갱신시켜줄 수 없다.

 

어떻게 접근해야될까?

 

이 문제는 우선순위 큐를 최소 힙으로 선언한 후 time을 기준으로 정렬하게 해 주면 된다.

그러면 cur에 대해서 가장 짧은 time을 가진 노드를 먼저 방문해주게 된다.

 

 

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
#include <iostream>
#include <queue>
using namespace std;
 
typedef pair<intint> pii;
int a[100001], n, k;
bool vis[100001];
priority_queue<pii, vector<pii>, greater<pii>> q;
 
int main() {
    cin >> n >> k;
 
    q.push({ 0,n });
    vis[n] = true;
 
    while (!q.empty()) {
        int cur = q.top().second;
        int time = q.top().first;
        q.pop();
        if (cur == k) break;
        for (int i : {cur - 1, cur + 1, cur * 2}) {
            if (0 <= i && i <= 100000 && !vis[i]) {
                vis[i] = true;
                if (i == cur * 2) {
                    a[i] = a[cur];
                    q.push({ time,i });
                }
                else {
                    a[i] = a[cur] + 1;
                    q.push({ time + 1,i });
                }
            }
        }
    }
 
    cout << a[k] << endl;
 
    return 0;
}
cs

 

기존 bfs코드와 다를 것 없이 priority_queue로만 바꿔주면 된다.

 

또 다른 방법이 있다. 바로 deque자료구조를 이용하는 것인데, deque는 priority_queue를 이용하는 것보다

더 빠르게 구할 수 있다!!

 

우선순위 큐의 특성상 삽입하는 데에 \(O(log N)\)의 시간 복잡도가 걸린다. 그러나 가중치가 0-1로만

이루어진 상황이라면 현재 위치 cur에서 다음에 이동할 부분은 0 또는 1만 차이 난다는 것을 알 수 있다.

 

그러니 deque의 앞쪽 부분에는 텔레포트(cur * 2) 하는 부분을 삽입해주고 cur - 1, cur + 1 부분은 1초가 걸리니

뒤에 삽입해주면 된다.

 

deque의 특성상 앞 뒤로 삽입하는 경우는 \(O(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
#include <iostream>
#include <deque>
using namespace std;
 
int n, k;
int vis[100001];
deque<int> dq;
 
int main() {
    cin >> n >> k;
 
    dq.push_back(n);
    vis[n] = 0;
 
    while (!dq.empty()) {
        int cur = dq.front(); dq.pop_front();
        if (cur == k) break;
        for (int i : {cur - 1, cur + 1, cur * 2}) {
            if (0 <= i && i <= 100000 && !vis[i]) {
                vis[i] = true;
                if (i == cur * 2) {
                    dq.push_front(i);
                    vis[i] = vis[cur];
                }
                else {
                    dq.push_back(i);
                    vis[i] = vis[cur] + 1;
                }
            }
        }
    }
 
    cout << vis[k] << endl;
 
    return 0;
}
cs

'BOJ' 카테고리의 다른 글

BOJ 1713 후보 추천하기  (0) 2021.01.01
BOJ 13913 숨바꼭질 4  (0) 2020.12.28
BOJ 12851 숨바꼭질 2  (0) 2020.12.28
BOJ 15686 치킨 배달  (0) 2020.12.25
BOJ 3190 뱀  (0) 2020.12.19

www.acmicpc.net/problem/12851

 

12851번: 숨바꼭질 2

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일 때

www.acmicpc.net

 

며칠 고민해봤는데 풀이 방법이 안 떠올라서 다른 블로그를 참고해서 풀었다.

두 개 정도의 풀이 방법이 있었는데 하나는 K로 가는 방법의 수를 배열 하나를 더 만들어서 접근하는 방법이고

다른 하나는 큐에서 팝 할 때 방문 체크를 해주는 방식이다.

 

첫 번째 방법은 시간이 항상 1씩 늘어난다는 것을 이용해서 d[next] == d[cur] + 1 이라면 cnt를 증가시키는 방법이다.

두 번째 방법은 현재 위치에서 팝 할때 방문처리를 해준다면 목적지 K는 항상 들어갈 수 있으므로

큐에 넣어주고 현 위치가 K이고 방문한 시간이 같다면 cnt를 증가시켜주는 방법이다.

 

 

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
#include <iostream>
#include <queue>
using namespace std;
 
int a[100001], cnt[100001], n, k;
bool vis[100001];
queue<int> q;
 
int main() {
    cin >> n >> k;
 
    vis[n] = true;
    q.push(n);
    cnt[n] = 1;
 
    while (!q.empty()) {
        int cur = q.front(); q.pop();
        for (int i : {cur - 1, cur + 1, cur * 2}) {
            if (0 <= i && i <= 100000) {
                if (!vis[i]) {
                    vis[i] = true;
                    q.push(i);
                    a[i] = a[cur] + 1;
                    cnt[i] = cnt[cur]; //이동가능하다면 현재까지의 경우의수 삽입
                } //현재 거리에서 1 더한값이 같다는 것은 이동 가능하다는 소리
                else if (a[i] == a[cur] + 1) cnt[i] += cnt[cur]; //경우의수 추가
            }
        }
    }
 
    cout << a[k] << endl;
    cout << cnt[k] << endl;
 
    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
#include <iostream>
#include <queue>
using namespace std;
 
int n, k, cnt, time;
bool vis[100001];
queue<pair<intint>> q;
 
int main() {
    cin >> n >> k;
 
    q.push({ n,0 });
    vis[n] = true;
 
    while (!q.empty()) {
        auto cur = q.front(); q.pop();
        vis[cur.first] = true;
        if (!time && cur.first == k) time = cur.second, ++cnt;
        else if (time == cur.second && cur.first == k) ++cnt;
        for (int i : {cur.first - 1, cur.first + 1, cur.first * 2}) {
            if (0 <= i && i <= 100000 && !vis[i]) q.push({ i,cur.second + 1 });
        }
    }
 
    cout << time << endl;
    cout << cnt << endl;
 
    return 0;
}
cs

'BOJ' 카테고리의 다른 글

BOJ 13913 숨바꼭질 4  (0) 2020.12.28
BOJ 13549 숨바꼭질 3  (0) 2020.12.28
BOJ 15686 치킨 배달  (0) 2020.12.25
BOJ 3190 뱀  (0) 2020.12.19
BOJ 1446 지름길  (0) 2020.12.16

 

글이 복잡하게 쓰여있지만 이해하기 그리 어렵지 않다.

result에 실패율이 높은 순으로 정렬해서 return 해주면 되는데 어떻게 실패율을 구할 것인가가 중요하다

우선 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수 / 스테이지에 도달한 플레이어 수 인데

현재 스테이지 개수 / 현재보다 크거나 같은 스테이지의 개수로 치환 가능하다.

 

따라서 전처리를 통해 stages의 원소들이 몇 번 등장했는지와 가장 큰 값을 구해놓는다.

가장 큰 값은 스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0으로 정의한다. 조건 때문에 필요한데

for 문을 돌리면서 i 값이 가장 큰 값보다 크다면 실패율을 0으로 push 해줘야 하기 때문이다.

 

pair벡터를 <int, double>로 선언해주는데 idx와 fail rate를 담는다.

 

첫 번째 예제를 보면

각각의 번호와 몇 번 등장했는지를 구해보면 이렇게 나오는데

스테이지의 총인원수가 8명이니

<1,1> <2,3> <3,2> <4,1> <5,0> <6,1> 

 

에서 1번의 실패율은 1의 second / n - sum(누적)이다.

 

 

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
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
 
int d[501];
 
bool comp(pair<intdouble>& a, pair<intdouble>& b) {
    if (a.second == b.second) return a.first < b.first;
    return a.second > b.second;
}
 
vector<int> solution(int N, vector<int> stages) {
    vector<int> answer;
    vector<pair<intdouble>> a; // idx, fail rate
    int n = stages.size();
    for (int i : stages) d[i]++;
    int m = *max_element(stages.begin(), stages.end());
    
    int sum = 0;
    for (int i = 1; i <= N; ++i) {
        if (i > m) a.push_back({ i,0 });
        else a.push_back({ i,(double)d[i]/(n - sum) });
        sum += d[i];
    }
    sort(a.begin(), a.end(), comp);
    
    for (auto i : a) answer.push_back(i.first);
    
    return answer;
}
cs

 

정렬은 comp를 통해 쉽게 구현 가능하다.

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

www.acmicpc.net/problem/1915 

 

1915번: 가장 큰 정사각형

첫째 줄에 n, m(1 ≤ n, m ≤ 1,000)이 주어진다. 다음 n개의 줄에는 m개의 숫자로 배열이 주어진다.

www.acmicpc.net

 

정사각형을 만족하기 위해서 어떤 규칙이 필요할까?

행렬 i, j 를 기준으로 왼쪽, 위, 왼쪽 위가 모두 1인 것만이 정사각형이 된다.

이걸 확장시켜주면, 최종적인 점화식은 \(D[i][j] = min(d[i-1][j], d[i][j-1], d[i-1][j-1]) + 1\) 이 된다.

물론 조건문으로 현재 위치가 1이고 그 주변도 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
#include <cstdio>
#include <algorithm>
using namespace std;
 
int a[1001][1001], n, m;
 
int main() {
    scanf("%d%d"&n, &m);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%1d"&a[i][j]);
 
    int res = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (a[i][j] && a[i - 1][j] && a[i][j - 1&& a[i - 1][j - 1]) {
                a[i][j] += min({ a[i][j - 1], a[i - 1][j - 1], a[i - 1][j] });
            }
            res = max(res, a[i][j]);
        }
    }
    printf("%d\n", res * res);
    
    return 0;
}
cs

 

a 배열에는 정사각형을 만족하는 크기가 들어가 있을테니 제곱의 형태로 출력해주면 된다.

'BOJ' 카테고리의 다른 글

BOJ 3190 뱀  (0) 2020.12.19
BOJ 1446 지름길  (0) 2020.12.16
BOJ 7579 앱  (0) 2020.12.13
BOJ 5052 전화번호 목록  (0) 2020.12.10
BOJ 5014 스타트링크  (0) 2020.12.10

+ Recent posts