just store Lunlun numbers in an array.좋은 문제를 발견하면, 그 문제의 뽕을 뽑아먹는(충분히 검토하는) 코뽕시간입니다 ㅎ
오늘의 코뽕문제는 AtCoder Beginner Contest 161 - D Lunlun Number가 되겠습니다.
이 문제는 설명이 단순하고 쉽기 때문에 나중에 다시 문제를 recall하기도 좋고 풀이도 다양해서 코뽕에 아주 적합한 문제가 되겠습니다.
참고로 이 Lunlun number는 OEIS에 등록되어 있습니다.
이문제는 대략 살펴보아도
브루트포스, 백트래킹, 이진탐색, Queue 등을 이용해서 풀 수 있는걸로 보입니다.
브루트 포스를 이용한 방법
먼저 브루트포스를 이용한 방법은, 단순히 1씩 증가시키면서 lunlun 넘버인지 보는코드에다가 일정부분을 스킵할 수 있는 코드를 삽입하는 간단한 방법입니다. 샘플코드는 다음과 같습니다.
예들들어 현재 숫자가 2
43일때 2가 violation이므로 둘째자리 숫자인 4가 9가 될때까지 50을 더해서 2
9
3까지 skip한다는 idea.
|
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
|
ll lun[100001];
int check_lunlun(ll i) {
int a = -1;
int jari = 1;
while (i) {
int ii = i % 10;
if (a == -1) a = ii;
else if (abs(a - ii) > 1) {
if (a > ii && a < 9)
return (jari / 10) * (10 - a - 1);
else return 1;
}
i /= 10; jari *= 10, a = ii;
}
return 0;
}
int main() {
int K; scanf("%d", &K);
int k = 1;
for (ll i = 1; k <= K; i++) {
ll skip = check_lunlun(i);
if (skip == 0) lun[k++] = i;
else i += skip - 1;
}
printf("%lld\n", lun[K]);
return 0;
}
|
cs |
이정도 아이디어만 가지고도 AC를 받기에는 충분(대략 700ms정도 걸림)
다른 아이디어도 적용하면 좀 더 스킵할수도 있을것임
아래는 다른사람들 방법
just store Lunlun numbers in an array.
근데 이건 원리상 아래 BFS랑 동일한거 같다.
백트래킹을 이용한 방법
678이라는 임의의 Lunlun넘버를 생각해 봤을때, 다음처럼 3가지 경우로 갈 수 있다고 생각하고, DFS를 돌리는 아이디어.
이건 실전에서 구현하기도 좋아보인다.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
map<ll, int> m;
void dfs(ll i) {
m[i] = 1;
if (i > 3234566667ll) return;
int ld = i % 10;
if(ld+1<=9) dfs(i * 10 + ld + 1);
dfs(i * 10 + ld);
if(ld-1>=0)dfs(i * 10 + ld - 1);
}
int main()
{
for (int i = 1; i < 10; i++) dfs(i);
int k; cin >> k;
int ix = 1;
for (auto a : m) {
if (ix++ == k) cout << a.first << endl;
}
return 0;
}
|
cs |
특별히 백트래킹이랄것도 없고.. 그냥 최대숫자보다 커지면 return하는게 다인데.. 저 최대숫자를 모르면 좀 애매하다는게 문제라면 문제.. DFS특성상 11111111111111 이런숫자를 먼저 최대자리수까지 파는 경향이 있기 때문에 더욱그렇다.
BFS를 이용한 방법
에디토리얼에서도 이걸 정해로 주장하고 있다.
뭐 기본적으로 DFS와 동일한 아이디어 인데, 최대숫자를 guessing할 필요가 없고 그냥, 값이 채워진게 10만번째이면 바로 break하면 되기 때문에 좀 더 안전성이 있다. 부채모양으로 퍼져나가니 찾자마자 최단거리가 되는 원리랑 조금 비슷한게 담긴거 같다.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
map<ll, int> m;
int main()
{
int k; cin >> k;
queue<ll> q;
for (int i = 1; i < 10; i++) q.push(i);
while (q.size()) {
ll n = q.front(); q.pop();
m[n] = 1;
if (m.size() > 100000) break;
if(n%10!=0) q.push(n * 10 + n % 10 - 1);
q.push(n * 10 + n % 10);
if(n%10!=9) q.push(n * 10 + n % 10 + 1);
}
int ix = 1;
for (auto a : m) {
if (ix++ == k) cout << a.first << endl;
}
return 0;
}
|
cs |
실전에서는 이코드처럼 정확히 10만에서 break하면 좀 위험할수도 있으니, 좀더 버퍼를 주는게 좋겠지만, 어쨌든 DFS보다는 나은 어프로치인듯하다.
덕북에 실행속도와 메모리 사용량에 있어서도 3배정도는 이득이 있는듯?
아래는 다른사람들 BFS구현
https://atcoder.jp/contests/abc161/submissions/11513177
https://atcoder.jp/contests/abc161/submissions/11518213
이진탐색을 이용한 방법
이진탐색+DigitDP 솔루션 : https://atcoder.jp/contests/abc161/submissions/11532810
이건 오버 엔지니어링 같아서 보기가 좀 싫어지네 ㅎ 나중에 보자.
'Programming > Problem Solving' 카테고리의 다른 글
| BST 트리 구현 (0) | 2020.04.09 |
|---|---|
| 인접행렬, 인접리스트 (1) | 2020.04.09 |
| Visual Studio Code (0) | 2020.04.03 |
| 코드포스 C++ 헬퍼(VsCaide) (0) | 2020.04.02 |
| C++ bigint class (1) | 2020.03.30 |
