재귀함수의 인자는 숫자의 번호라고 생각하면 되겠다. 즉 k가 1인경우는, 첫번째 숫자를 결정할 차례라는 뜻이다.
길이를 M으로 입력받기 때문에, k가 M+1이 되면 M+1번째 숫자를 결정할 차례라는 의미이므로 이미 M번째 까지는 결정이 되었다는 의미이다.
따라서 k == M+1인 경우를 base condition으로 설정해주면 된다.
또한 재귀를 빠져나온 이후에는, 숫자를 사용중이 아닌 것이 되기때문에, isused값을 다시 false로 바꿔줘야한다.
만약 k를 전역변수로 두고 코딩을 한다면 k또한 재귀를 들어가기전에는 증가, 재귀에서 빠져 나온 이후에는 감소를 해줘야 할 것이다.
#include<iostream>
#include<algorithm>
using namespace std;
int N, M;
int arr[10], num[10];
bool isused[10];
void func(int k) {
if (k == M + 1) {
for (int i = 1; i <= M; i++)
cout << arr[i] << ' ';
cout << '\n';
return;
}
for (int i = 1; i <= N; i++) {
if (!isused[i]) {
arr[k] = num[i];
isused[i] = true;
func(k + 1);
isused[i] = false;
}
}
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> N >> M;
for (int i = 1; i <= N; i++) {
cin >> num[i];
}
sort(num + 1, num + N + 1);
func(1);
return 0;
}
- 움직이는 방법은, 내 위치가 X였다면 1초 이후에 X-1, X+1, 그리고 2*X 이렇게 가능하다.
- 이때 한 번 움직일 때 1초씩 흐른다.
- 나의 위치 X에서 친구의 위치까지 이동하는 데에는 몇 초가 걸릴까?
위의 상황을 착실하게 구현해주면 된다.
먼저 이 문제는 기계적으로 배열 크기를 잡는 모든 이들을 위한 문제라고 할 수 있다.
(물론 거기에는 나도 포함되었다)
이 문제의 구현 수준은, 절대 24%대의 정답률이 나올만한 것이 아니다.
다만 대부분의 사람들이 배열의 크기를 잡을 때 n값의 범위만을 고려했기 때문에 '맞왜틀'을 반복했을 것이다.
나 또한 초반에는 그렇게 생각했다.
1차적으로 이것을 파악할 수 있는 부분은 문제의 힌트에 있다.
5에서 17을 가는 길에 18을 거친다. 이것을 보고 내가 만약에 10,0000을 목적지로 잡았다고 하면, 이 위치보다 큰 값을 거쳐서 저 위치로 다다를 가능성도 없지 않다는 것이다.
필자의 경우에는, 이 힌트를 보고도 이것을 파악하지 못했고, 몇 가지의 예시를 가지고 print를 찍어보는 방식으로 디버깅을 하던 도중에 깨달았다.
또, 여러가지의 예시를 넣어보는 과정을 거친 이후에도 해결되지 않는 문제들은 대부분이 극값 혹은 그 근처에서 발생하는 문제였다. 이번 경우에도 그렇다고 볼 수 있다.
정확한 배열 크기는 알아내지 못하였고. 그저 배열의 크기를 넉넉하게 잡아주는 방법으로 해결했다.
#include<iostream>
#include<queue>
using namespace std;
int n, k;
int vis[300000];
queue<int> q;
int sec = 0;
void bfs(int start) {
q.push(start);
vis[start]++;
while (!q.empty()) {
int cur = q.front();
q.pop();
for (int i = 0; i < 3; i++) {
int np;
if (i == 0)
np = cur - 1;
else if (i == 1)
np = cur + 1;
else
np = 2 * cur;
if (np < 0 || np > 100000 || vis[np] >= 0) continue;
q.push(np);
vis[np] = vis[cur] + 1;
if (np == k) return;
}
}
}
int main(void) {
cin >> n >> k;
for (int i = 0; i < 300000; i++)
vis[i] = -1;
bfs(n);
cout << '\n';
for (int i = 0; i < 30; i++)
printf("%d 에서 %d\n", i, vis[i]);
cout << '\n';
cout << vis[k] << '\n';
return 0;
}
첫번째 자리의 숫자를 정할 때, 이전에 쓰인 숫자가 없기 때문에, 이 경우에만 st를 1로 정해주면 된다.
#include<iostream>
using namespace std;
int N, M;
int arr[9];
void func(int k) {
if (k > M) {
for (int i = 1; i <= M; i++) {
cout << arr[i] << ' ';
}
cout << '\n';
return;
}
int st = 1;
if (k != 1) st = arr[k - 1];
for (int i = st ; i <= N; i++) {
arr[k] = i;
func(k + 1);
}
}
int main(void) {
cin >> N >> M;
func(1);
return 0;
}
이전까지는 숫자의 중복을 제한하기 위해서 isused배열을 사용했다. 숫자가 arr배열을 이루는 데에 사용되고 있다면 true 값을 가지도록 하고 그렇지 않은 경우 false 값을 가지도록 하였다.
이번에는 이것이 필요하지 않다.
또한 문제를 풀이하는 과정에 있어서, 배열을 인자로 넘기지 않고 전역변수로 사용해도 좋다.
k값도 마찬가지이다. k값을 인자로 넘기지 않으려면, 재귀에 들어가기 전에 k값을 증가시키고,
재귀에서 탈출한 이후에는 k값을 줄여줘야한다.
또한 k를 0부터 시작할지 1부터 시작할지도 편한 데로 선택하면 되겠다.
나 같은 경우에는 k를 0부터 시작하는 경우, ~까지는 수열이 만들어져 있다는 의미로 보았다.
1부터 시작하는 경우에는, 이번에는 ~번째 자리의 숫자를 채울 차례다라는 의미로 생각하면 되겠다.
당연하게도 의미가 다르기 때문에 base condition의 조건도 달라져야 한다.
전자의 경우 k==m인 경우가 기저 조건이고, 후자의 경우 k > m 인 경우를 기저 조건이라고 보면 된다.
//전역변수 활용
#include<iostream>
using namespace std;
int arr[8], N, M; //1 indexed
//int k = 0;
void func(int k) {
if (k > M) {
for (int i = 1; i <= M; i++)
cout << arr[i] << ' ';
cout << '\n';
return;
}
for (int i = 1; i <= N; i++) {
arr[k] = i;
func(k + 1);
}
}
int main(void) {
cin >> N >> M;
func(1);
return 0;
}
중복이 없다는 조건을 만족시키기 위해서 특정 숫자가 사용되었는지 관리하기 위해서 isused 배열을 사용한다.
그리고 수열이 되는 숫자는 arr 배열에 저장된다.
재귀함수로 구현을 할 것이고, base condition은 수열의 길이 k = M이 되는 경우이다.
이때 수열이 완성되었으므로 출력을 해준다.
재귀함수를 빠져나온 이후에는 그 숫자가 사용중인 것이 아니게 되기 때문에 isused를 다시 false로 만들어주는 것이 중요하다.
arr값은 어짜피 이어서 덮어씌워질것이기때문에 고려하지 않아도 된다.
이 문제는 next_permutation을 활용해서도 구현이 가능할 것이다.
#include<iostream>
using namespace std;
int N, M;
void func(int* arr, bool* isused, int k) {
if (k == M) {
for (int i = 1; i <= M; i++)
cout << arr[i] << ' ';
cout << '\n';
return;
}
for (int i = 1; i <= N; i++) {
if (!isused[i]) {
arr[k + 1] = i;
isused[i] = true;
func(arr, isused, k + 1);
isused[i] = false;
}
}
}
int main(void) {
int arr[10];
bool isused[10];
for (int i = 1; i <= 9; i++) {
arr[i] = 0;
isused[i] = false;
}
int k = 0;
cin >> N >> M;
func(arr, isused, k);
return 0;
}