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

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

www.acmicpc.net/problem/7579

 

7579번: 앱

입력은 3줄로 이루어져 있다. 첫 줄에는 정수 N과 M이 공백문자로 구분되어 주어지며, 둘째 줄과 셋째 줄에는 각각 N개의 정수가 공백문자로 구분되어 주어진다. 둘째 줄의 N개의 정수는 현재 활

www.acmicpc.net

 

배낭 문제의 변형이다. 메모리와 비용이 주어지는데 dp테이블을 메모리를 기준으로 채워야 하나?

생각했는데 비용을 기준으로 dp테이블을 채워줘야 한다.

 

예제를 보면 

 

30 10 20 35 40

3 0 3 5 4

 

가 주어지는데 

0   1   2  3   4  5   6   7  8  9   10   11   12  13   14  15

10 10 10 40 50 50 60 80 80 85 100 100 115 115 115 135

이런 식으로 테이블을 채워주고 그때의 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
#include <iostream>
#include <algorithm>
using namespace std;
 
int n, k, sum, w[101], v[101], d[100001];
 
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
 
    cin >> n >> k;
    for (int i = 0; i < n; ++i) cin >> w[i];
    for (int i = 0; i < n; ++i) cin >> v[i], sum += v[i];
 
    for (int i = 0; i < n; ++i)
        for (int j = sum; j >= v[i]; --j)
            d[j] = max(d[j], d[j - v[i]] + w[i]);
    
    //for (int i = 0; i <= sum; ++i) cout << d[i] << ' ';
    //cout << endl;
 
    int i;
    for (i = 0; i < sum && d[i] < k; ++i);
    cout << i << endl;
 
    return 0;
}
cs

 

'BOJ' 카테고리의 다른 글

BOJ 1446 지름길  (0) 2020.12.16
BOJ 1915 가장 큰 정사각형  (0) 2020.12.13
BOJ 5052 전화번호 목록  (0) 2020.12.10
BOJ 5014 스타트링크  (0) 2020.12.10
BOJ 11066 파일 합치기  (0) 2020.12.05

www.acmicpc.net/problem/5052

 

5052번: 전화번호 목록

첫째 줄에 테스트 케이스의 개수 t가 주어진다. (1 ≤ t ≤ 50) 각 테스트 케이스의 첫째 줄에는 전화번호의 수 n이 주어진다. (1 ≤ n ≤ 10000) 다음 n개의 줄에는 목록에 포함되어 있는 전화번호가

www.acmicpc.net

 

트라이를 사용하는 문제지만 map을 활용해서 접두사 트리를 만들고 전화번호를 만드는 중에 이미 존재하는 전화번호가 있다면 YES 아니면 NO를 출력해주면 된다.

map을 <string, bool> 로 선언하고 string 부분은 전화번호, bool 부분은 완성된 전화번호인지? 를 판단하는 변수다

 

<9,1>

<91,1>

<911,2>

 

이런 식으로 처리해줘서 중간에 2가 나온다면 접두사에 완전한 전화번호가 존재한다는 뜻이니 NO를 출력해주면 된다.

 

 

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 <iostream>
#include <string>
#include <unordered_map>
using namespace std;
 
unordered_map<stringint> m;
string s[10001];
int tc, n;
 
inline bool go() {
    for (int i = 0; i < n; ++i) {
        string tmp;
        for (int c = 0; c < int(s[i].size()) - 1++c) {
            tmp += s[i][c];
            if (m[tmp] == 2return false;
        }
    }
    return true;
}
 
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
 
    cin >> tc;
    while (tc--) {
        cin >> n;
        m.clear();
        for (int i = 0; i < n; ++i) {
            cin >> s[i];
            string tmp;
            for (int c = 0; c < s[i].size(); ++c) {
                tmp += s[i][c];
                if (m[tmp] == 0) m[tmp] = 1;
            }
            m[tmp] = 2;
        }
 
        if (go()) cout << "YES" << '\n';
        else cout << "NO" << '\n';
    }
 
    return 0;
}
cs

 

 

'BOJ' 카테고리의 다른 글

BOJ 1915 가장 큰 정사각형  (0) 2020.12.13
BOJ 7579 앱  (0) 2020.12.13
BOJ 5014 스타트링크  (0) 2020.12.10
BOJ 11066 파일 합치기  (0) 2020.12.05
BOJ 10164 격자상의 경로  (0) 2020.12.03

+ Recent posts