just store Lunlun numbers in an array.좋은 문제를 발견하면, 그 문제의 뽕을 뽑아먹는(충분히 검토하는) 코뽕시간입니다 ㅎ
오늘의 코뽕문제는 AtCoder Beginner Contest 161 - D Lunlun Number가 되겠습니다.
이 문제는 설명이 단순하고 쉽기 때문에 나중에 다시 문제를 recall하기도 좋고 풀이도 다양해서 코뽕에 아주 적합한 문제가 되겠습니다.
참고로 이 Lunlun number는 OEIS에 등록되어 있습니다.
이문제는 대략 살펴보아도
브루트포스, 백트래킹, 이진탐색, Queue 등을 이용해서 풀 수 있는걸로 보입니다.
브루트 포스를 이용한 방법
먼저 브루트포스를 이용한 방법은, 단순히 1씩 증가시키면서 lunlun 넘버인지 보는코드에다가 일정부분을 스킵할 수 있는 코드를 삽입하는 간단한 방법입니다. 샘플코드는 다음과 같습니다.
예들들어 현재 숫자가 243일때 2가 violation이므로 둘째자리 숫자인 4가 9가 될때까지 50을 더해서 293까지 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 |
---|---|
인접행렬, 인접리스트 (0) | 2020.04.09 |
Visual Studio Code (0) | 2020.04.03 |
코드포스 C++ 헬퍼(VsCaide) (0) | 2020.04.02 |
C++ bigint class (0) | 2020.03.30 |