묻고 답해요
169만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
2240번 자두나무 질문있씁니다!
안녕하세요 선생님! 제가 이해하는 것이 맞나 싶어서 여쭤보고자 질문올립니다!Q1.밑에 이부분에서는 go(0,1,m-1)같은 경우와 go(0,0,m)는 완탐 시 처음 시작하자마자 움직이는 경우에 수를 나누어서 쭉쭊죾 한다음에 max값을 찾기 위해 구현한 것이 맞을까요?cout << max(go(0, 1, m - 1), go(0, 0, m)) << '\n'; Q2.밑에 이 부분에서 ret을 참조자로 받아서 반환하는 이유가 혹시 있을까요? 참조자를 사용하지 않으면 시간초과가 나더라구요.. 참조자를 통해서 직접 적으로 dp배열의 값을 참조하면 메모리를 효율적으로 쓸수 있어서 그런건가여? 근데 또 궁금하게 int &ret을 계속 생성하는건데.. 조금 햇갈립니다..ㅠint &ret = dp[idx][tree][cnt]; if(~ret) return ret; Q3.이 부분은 현재의 index에서 다음 인덱스로 갈떄 옆에 트리로 가는경우 안가는경우나눠지는 것으로 해석하였습니다. 그런데 뒤에 go함수 같은경우는 나무이동을 안할떄로 알고 있씁니다. 뒤에 (tree ==b[idx]+1) 같은 경우는 다음 go로 넘어가기 전 현재의 위치에 tree와 그 시간대 tree에 위치가 같으면 +1 (idx시간 떄 자두를 받았기 떄문) 아니면 0을 더하는 것 이 맞나요?!?return ret = max(go(idx + 1, tree^1, cnt - 1), go(idx + 1, tree, cnt)) + (tree == b[idx] - 1);Q4. 이건 문제와 외람된 말이긴 합니다. 지금 매 주차 개념설명 들으며 2~3문제 씩 주차 문제 풀면서 다음 주차 개념을 빠르게 듣고 있습니다. 과정이 너무 어려운데 이해가 안되면 문제를 외우기보다는 그 과정이 어떤식으로 대처해야하는지 위주로 공부하고 있습니다. 잘하고있는걸까여ㅠ,,
-
미해결홍정모의 따라하며 배우는 C++
코드 오류 관련 질문드립니다.
#include <iostream> #include "a.cpp" using namespace std; static int g_a = 1; //void doSomething(); int main() { int a = 10; doSomething(); return 0; } #include <iostream> void doSomething() { using namespace std; cout << "Hello " << endl; }a.cpp가 아래와 같다고 할 때, 강의에서는 이렇게 코딩하는 경우는 거의 없지만 그래도 가능은 하다고 하셨는데, 실제로 컴파일해보니 오류가 발생합니다. 왜 오류가 나는지 모르겠습니다!
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
7_A 2분 쯤 설명이 이해가 안됩니다.
코드를 아무리 봐도 DP에 넣은 값들이 여태까지 지나온 경로들의 최적해가 아니라 visited에 포함되지않은 남은 경로들의 최적해 인거같아요.... 설명에서는 앞에서부터 쌓아가는거 처럼 설명하시는데( (a b c)든 (a c b)든 최적의 값을 구해서 d로 가면 되는거아니냐는 부분) 제가 이해를 잘못 한건가요???
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
4분 54초에 combi 외우라고 어디에서 말씀 하셨나요?
블로그 완탐 글 읽는데 이문제에서는 왜 visited 처리 안하셨는지 궁금합니다! 아 그리고 combi(-1,v)로 시작하셨던데 start +1 안하고 그냥 combi(0,v)로 하면 안되나요?
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
교안 p131 3개의 멤버변수 정렬하기
해결되었습니다.
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
5-H 질문있습니다.
while(e<n){ if(cnt[a[e]]==0){ cnt[a[e]]++; e++; } else{ ret+=(e-s); cnt[a[s]]--; s++; } }강사님 안녕하세요?else문에서 cnt[a[s]]-- 대신 cnt[a[e]]--로 하면 틀리는 이유를 모르겠습니다. 어차피 a[s]랑 a[e]는 똑같은 값이어서 어떤 것을 줄여도 맞아야하는거 아닌가요?http://boj.kr/b07dba8700854c70b5f4031fbd5239c1
-
미해결[게임 프로그래머 도약반] DirectX11 입문
[2-4. 좌표계 변환] 제가 이해한게 맞는지 확인 부탁드려용!
항상 감사드립니다!강의를 들으면서 제가 이해한대로 내용의 핵심만 정리 해보았는데요.제가 이해한게 맞는지 확인 해주시면 정말로 감사드리겠습니다!1. 이렇게 이해한게 맞을까요?u... v... w... 들은 A좌표계의 단위 벡터들을 B좌표계 기준으로 분해한 성분들을 의미한다. 만약 A좌표계가 원점(0, 0, 0)이면, 단위 벡터 u = [1, 0, 0], v = [0, 1, 0], w = [0, 0, 1]일 텐데이런 기준이 되는 단위 벡터를 B좌표계의 시점에서 자신의 단위 벡터를 기준으로 표현하면각각 U = [ux, uy, uz], V = [vx, vy, vz], W= [wx, wy, wz]라는 말이다. 이때 ux, uy, uz같은 성분들은 B좌표계를 기준으로 A 좌표계의 단위 벡터 u의 각각의 성분으로 표현한 값이다.그리고 Qx, Qy, Qz는 B좌표계 중심점을 기준으로한 A좌표계의 중심점의 위치를 의미한다. 진짜 최종적으로 정리해서... 우리는 B좌표계 기준의 단위 벡터들 U, V, W를 A 좌표계의 단위 벡터로 표현한 성분 정보(ux, u...)들만있으면 A 좌표계의 어떤 위치들이라도 B 좌표계 기준의 위치 정보를 얻어내는게 가능하게 된다.Qx, Qy, Qz는 얻기가 쉽다. (다른 좌표계면 당연히 해당 좌표계의 위치 정보를 알고 있을테니)-----------------------------------------2. 만약 마지막 원소를 1이 아닌 0으로 바꿀 경우강사님께서 "A좌표계의 방향 벡터가 B좌표계에서는 어떤 값으로 표시되는지 알고 싶을 때 사용한다"라고 말씀하셨는데마지막 원소가 날아가버린다면 계산시 Qx, Qy, Qz정보가 날아가버린다는 의미이므로.A 좌표계에서의 방향 벡터를 B기준에서의 방향 벡터로 변환한다라고 봐도 무방할까요?
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
3-L 질문
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요 선생님http://boj.kr/cd54b57de0df4ce294ae9ff069c83984next를 변수를 선언하는 것과 다음과 같이 코드를 작성하는 것에 왜 값이 다르게 출력이 되는지 여쭤보고 싶습니다. 제 코드를 돌리면 이렇게 나와요!
-
해결됨10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
[5-L] 브루트포스 방법 문의드립니다...!
https://www.acmicpc.net/source/73585978 시간초과가 발생하는데, 어느 부분을 수정해서 복잡도를 줄여야할지 잘 모르겠어요..!dfs를 실행하는 반복문을 절반으로 줄이는 방식으로 해야할까요...?
-
해결됨it 취업을 위한 알고리즘 문제풀이 입문 (with C/C++) : 코딩테스트 대비
4번 나이차이 문제
#include <iostream> using namespace std; int main() { int n,a; int max = 0; int min = 0; cin >> n; for (int i = 1; i <= n; i++) { cin >> a; if (a > max) { max = a; } if (a < min) { min = a; } } cout << max - min; return 0; }이렇게 했을 때 값이 제대로 나오지 않습니다.초기화 부분에서 max와 min에 0을 넣으면 왜 값이 다르게 나오나요..?
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
5-A
와.. 일단 저는 다른 방법으로 풀었는데제가 푼 방식으로의 접근에 익숙해지면 더 난이도 높아지는 그리디 문제는 대처를 못하겠죠? ㅠ..큰돌님 로직이 큰 가격만 남게되는건 쉽게 이해했는데if(pq.size() > v[i].first)이 코드 하나로 큰 가격 + 하나의 날짜에 하나만 꽂기가가능해지는것에 이마를 탁 치고 갑니다... 그래도 제 코드 한번 봐주시고 피드백 한번 주시면 감사하겠습니다.저는가격으로 내림차순 sort한다.visited[10004]를 만들어놓는다.가장 큰 가격부터 자신의 Day에 visited[Day] = true로 해준다.만약 자신의 Day에 visited[Day]가 이미 true라면Day-1부터 1일까지 visited[]가 false일 날을 찾아 거기에 넣어준다.(찾았으면 break)이 로직으로 풀었습니다!https://www.acmicpc.net/source/73577847
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
6-B 누적합에서 보는 이득이 클까요?
http://boj.kr/e1c4b7529c7d4925bb95b0e38d7aec56처음에는 1~10억으로 이분탐색을 했었는데요시간초과가 나서 배열에 있는 값들을 더하고 확인하는 시간이 오래 걸리나 싶어서 누적합으로 해서 풀었는데 큰 차이는 없었습니다. 못풀어서 결국 강의 봤는데if (mx > mid) return false; 부분을 보고 감탄을 금치 못했는데요..누적합으로 바꿨을 때 답이 아니었던게 좀 충격이었던지라누적합을 이런 용도로 사용하는 것이 아닌가?라는의문이 들기도 하고 .. 누적합의 퍼포먼스를 최대로 낼 수 있는 문제가 막 떠오르지가 않아서 잘 이해하고 있는지 의문이 들어 글 남겨봅니다 ㅜㅜ
-
미해결[게임 프로그래머 입문 올인원] C++ & 자료구조/알고리즘 & STL & 게임 수학 & Windows API & 게임 서버
(게임수학 - 역삼각함수) 벡터 외적으로 시계/반시계 방향 체크 하는 부분 질문 드립니다
안녕하세요 선생님, 강의 열심히 듣고 있습니다! 먼저 질문부터 말씀 드리자면, 벡터A X 벡터B일 때, 벡터 B가 시계방향에 있음에도 왜 코드에서는 외적(Cross)값이 양수가 나오는지 궁금합니다! 벡터 외적으로 벡터들 간의 상대적인 위치(시계/반시계) 구하는 방법 공부하는데, 잘 이해가 되지 않아 구글이나 다른 자료를 통하여 벡터 외적 쪽을 추가적으로 공부하였습니다.2차원 평면 상에서 하기와 같이 벡터a x 벡터b 를 했을 때, 양수가 나오면 벡터b는 벡터a에 대해 '반시계'방향으로 있으며, 음수가 나오면 벡터b는 벡터a에 대해 '시계'방향으로 나온다고 설명 되어 있으며, 다른 자료들을 찾아봐도 다 위와 같이 나와있더라구요. (출처 : https://bowbowbow.tistory.com/14 ) 다만 강의 코드에서는 아래와 같이 몬스터가 바라보는 방향(lookDir)벡터에서 몬스터에서 마우스로의 방향(MonsterToMousedir)을 외적 계산하였을 때, 이때 마우스 방향이 몬스터 기준으로 오른쪽('시계방향')으로 있으면 cross 값이 음수가 나와야 하지 않나 싶은데 실제로는 cross 값이 양수가 나오더라구요. 강의에서도 cross값이 0미만(음수)일 때는 반시계 방향이 있게 되므로 이때 값 보정을 위해 angle에 360-angle 처리하는 것으로 나와 있는 것으로 보니 반시계 방향일 때 음수가 되는 것이 맞는 것 같기는 한데,, 왜 이 코드에서는 양수가 나오는지 궁금합니다.수학적 지식이 너무 없어서 그런가 암만 코드를 봐도 왜 이렇게 되는지 잘 이해가 안 되네요ㅠ 도움 주시면 감사 드리겠습니다
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
3-K 시간초과 & 학습 방법 고민있어요
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요. 강의 잘 듣고 있습니다.강의를 참고하여 풀었는데. 시간초과가 뜹니다#include <bits/stdc++.h> using namespace std; int R, C; vector<vector<char>> lake; queue<vector<int>> candidates_Swan, candidates_SwanTemp; queue<vector<int>> candidates_Water, candidates_WaterTemp; vector<vector<int>> delta = {{-1,0},{1,0},{0,-1},{0,1}}; vector<vector<int>> visitedSwan, visitedWater; bool moveSwan(){ while(candidates_Swan.size()){ vector<int> now = candidates_Swan.front(); candidates_Swan.pop(); for(auto d : delta){ int next_i = now[0]+d[0]; int next_j = now[1]+d[1]; if (next_i >= 0 && next_j >= 0 && next_i < R && next_j < C){ if (visitedSwan[next_i][next_j] == 0){ visitedSwan[next_i][next_j] = 1; if (lake[next_i][next_j] == '.'){ candidates_Swan.push({next_i, next_j}); } else if (lake[next_i][next_j] == 'X'){ candidates_SwanTemp.push({next_i, next_j}); } else if (lake[next_i][next_j] == 'L') return true; } } } } return false; } void waterMelting(){ while(candidates_Water.size()){ vector<int> now = candidates_Water.front(); candidates_Water.pop(); for(auto d : delta){ int next_i = now[0] + d[0]; int next_j = now[1] + d[1]; if (next_i >= 0 && next_j >= 0 && next_i < R && next_j < C){ if (visitedWater[next_i][next_j] == 0){ if (lake[next_i][next_j] == 'X'){ candidates_WaterTemp.push({next_i, next_j}); visitedWater[next_i][next_j] = 1; lake[next_i][next_j] = '.'; } } } } } return; } int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); cin >> R >> C; lake = vector<vector<char>>(R, vector<char>(C)); visitedSwan = vector<vector<int>>(R, vector<int>(C,0)); visitedWater = vector<vector<int>>(R, vector<int>(C,0)); for(int i = 0 ; i < R ; ++i){ string s; cin >> s; for(int j = 0 ; j < C; ++j){ lake[i][j] = s[j]; if (lake[i][j] == 'L' && candidates_Swan.empty()){ candidates_Swan.push({i,j}); // 백조는 한마리 위치에서만 시작 visitedSwan[i][j] = 1; } if (lake[i][j] == 'L' || lake[i][j] == '.'){ candidates_Water.push({i,j}); visitedWater[i][j] = 1; } } } int day = 0; while(true){ if (moveSwan()) break; waterMelting(); // cout << endl; // for(auto ll : lake){ // for(auto l : ll) cout << l; // cout << endl; // } // cout << endl; candidates_Swan = candidates_SwanTemp; candidates_Water = candidates_WaterTemp; candidates_WaterTemp = queue<vector<int>>(); candidates_SwanTemp = queue<vector<int>>(); day++; } cout << day << "\n"; return 0; } 강의를 듣기 전에 먼저 문제를 풀고 강의를 듣는 방식을 고수하고 있는데, 한 문제를 푸는데 점점 시간이 늘어나 두시간 정도를 써야 겨우 한문제를 풀고 있습니다.이런 방식을 고수하는것이 좋을지,어떻게 해야하나 질문드려요. 감사합니다. ^^
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
질문있습니다.
http://boj.kr/0aeaba2d60a745ba87e41316d0804d89위 코드를 디버깅 해보면 v.clear()를 실행 시킨 후 dfs함수로 들어가서 v.push_back()을 하면 오류가 발생합니다.오류:"Unhandled exception thrown: read access violation._Pnext was 0x8."왜 이런 오류가 발생하는지 궁금합니다. 해결방안도 알고 싶습니다.
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
2792번 보석상자 질문있습니다!
안녕하세요, 선생님 ! 2792번 선생님 코드에 질문이 있어 질문 남깁니다.check()에서 return n>=num이 약간 이해가 안됩니다.처음 저는 n>num이라고 생각했었습니다. n=num이 될 떄의 값이 최적해 겠구나 생각했었습니다.아니면 혹은 n>num일 떄도 정답이 될 수 있어서 그런 것 일까요?!?
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
3-B 시간복잡도
http://boj.kr/efeea39f5e6946e3a9982024980b4089이 코드의 최악의 시간복잡도를 board가 모두 'L' 인 경우에 n*m*bfs--->n*m*n*m이라고 생각했는데 맞게 계산할 것인가요?
-
해결됨홍정모의 따라하며 배우는 C++
강의 내용과 object slicing에 대해 질문이 있습니다.
지금까지 들은 강의에서는 매개변수에 &가 있는 경우에는 call by reference로 동작하고, copy를 하지 않는 방식으로 알고 있었습니다. 그리고 call by value로 동작하는 경우에는 상황에 따라서 object slicing이 발생할 가능성이 있다고 이해했었습니다.그런데 강의에서 아래 코드처럼 &이 있는데 object slicing이 발생하신다고 하셔서 몹시 혼란스럽더라구요.catch(Exception& e) { e.report(); }그래서 다른 분들의 질답글과 C++ 표준(n3690을 참고했습니다)을 찾아봤습니다.Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable named in the matching handler (15.3). If the type of the exception object would be an incomplete type or a pointer to an incomplete type other than (possibly cv-qualified) void the program is ill-formed. Evaluating a throw-expression with an operand throws an exception; the type of the exception object is determined by removing any top-level cv-qualifiers from the static type of the operand and adjusting the type from “array of T” or “function returning T” to “pointer to T” or “pointer to function returning T,” respectively- C++ ISO n3690 15.1/3내용을 보니 throw를 하게 되면 exception object(예외 객체)라는 것을 copy-initialize하고, 해당 객체는 l-value이고 일치하는 handler에서 변수를 초기화하기 위해 사용된다고 되어 있었습니다.그리고 영상에서 rethrow 시 throw; 처럼 피연산자가 없는 경우 object slicing이 발생하지 않는다고만 나와서 설명이 좀 빈약한 것 같아 더 찾아봤습니다.A throw-expression with no operand rethrows the currently handled exception (15.3). The exception is reactivated with the existing exception object; no new exception object is created. The exception is no longer considered to be caught; therefore, the value of std::uncaught_exception() will again be true.- C++ ISO n3690 15.1/8throw;의 경우 새로운 exception object를 생성하지 않고, 기존 exception object로 다시 예외를 활성화시킨다고 나와있었습니다.좀 정확하게 확인하려고 예외 객체의 주소를 각 시점에 출력하도록 했습니다.class MyArray { private: int m_data[5]; public: int& operator [](const int& index) { if (index < 0 || 5 <= index) { ArrayException e; cout << &e << endl; throw e; } return m_data[index]; } }; void doSomething() { MyArray my_array; try { my_array[100]; } catch (Exception& e) { cout << "doSomething()" << endl; cout << &e << endl; e.report(); throw e; } } int main() { try { doSomething(); } catch (Exception& e) { cout << "main()" << endl; cout << &e << endl; e.report(); } return 0; }[] 연산자로 범위를 벗어난 인덱스에 접근했을 때 예외 객체를 생성하고doSomething() 함수의 catch() 내에서main() 함수의 catch() 내에서이렇게 확인했는데, 위에서 확인했던 내용대로 주소가 모두 달랐습니다. 그리고 doSomething() 에서 rethrow 를 throw;로 변경하니 2번과 3번의 출력 주소가 같았습니다.종합해보면 throw로 전달되는 객체의 복사 여부는 catch()의 &에 따라 달라지는 것이 아니고, throw에 피연산자가 생략되어 있냐 없냐로 달라지는 것 같더라구요. 그 마저도 throw; 처럼 작성하는 것은 rethrow할 때만 가능한 것 같았습니다.다음으로 그렇다면 왜 catch()에서 참조를 이용하는지 아래 링크를 참고했습니다.https://wiki.sei.cmu.edu/confluence/display/cplusplus/ERR61-CPP.+Catch+exceptions+by+lvalue+reference참고해보니 예외 클래스가 상속 관계를 가지는 경우, 예외 객체를 초기화하는 과정에서 object slicing이 발생할 수 있기에 &를 추가한다고 되어 있었습니다.실제로 주소 출력을 했던 테스트 코드에서 doSomething()에서는 throw;로 작성하더라도 main()의 catch()에서 &을 지우니 2번과 3번의 출력 주소가 달라졌습니다.그리고 생각을 해보니 throw는 expression이지 함수는 아니고, 더 찾아보니 'throwing by reference' 같은 개념은 존재하지도 않더라구요.결론적으로 함수에서와 throw 문에서의 &는 참조라는 같은 의미로 사용되지만, 함수의 매개변수에 사용하는 &는 call by reference로 작동하기 위한 것이고 catch()에서 사용하는 &는 object slicing을 피하기 위한 것이라고 이해하면 될까요?글이 조금 난잡할 수도 있는데, 읽어주셔서 감사합니다.
-
해결됨10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
교안 108p insert, erase
안녕하세요 🙂 큰돌님교안 108p에 있는 예제코드를 제가 insert와 erase를 이해하기 위해서 아래와 같이 변경하였는데요.#include <bits/stdc++.h> using namespace std; list<int> a; void print(list<int> a) { for (auto it : a) cout << it << " "; cout << '\n'; } int main() { for (int i = 1; i <= 3; i++) a.push_back(i); // a = 1 2 3 for (int i = 1; i <= 3; i++) a.push_front(i); // a = 3 2 1 1 2 3 auto it = a.begin(); it++; a.insert(it, 1000); // 3 1000 2 1 1 2 3 a.insert(it, 2000); // 3 1000 2000 2 1 1 2 3 print(a); it = a.begin(); it++; cout << "*it : " << *it << '\n'; a.erase(it); print(a); cout << "*it : " << *it << '\n'; a.pop_front(); a.pop_back(); print(a); cout << a.front() << " : " << a.back() << '\n'; a.clear(); return 0; }다음과 같이 변경해서 출력하면,3 1000 2000 2 1 1 2 3*it : 10003 2000 2 1 1 2 3*it : 22000 2 1 1 22000 : 2이렇게 나오는데, insert와 erase 메서드 모두 매개변수로 전달받은 iterator에다가 각각의 기능을 실행한 뒤 그 다음 위치(그 다음 인덱스)를 가리키도록 바꿔주는 걸까요?제 예상으로는 출력의 두 번째 *it 이 2000으로 나올 것으로 예상했는데, 2가 나와서a.erase(it);를 했을 때, it이 인덱스 1을 가리켜서 1000을 지우고 난 뒤, 그 다음 인덱스인 2를 가리키게 돼서 2를 가리키게 된 것으로 이해하였는데 맞을까요??마찬가지로 위의 insert도 인덱스 1 위치에서 삽입을 한 뒤, it은 인덱스 2를 가리키게 되고, 또 insert 해서 마지막엔 it이 인덱스 3을 가리키는 로직으로 이해하였습니다! 혹시 이러한 로직이 맞다면, list만 이런 것인지 다른 자료구조의 insert도 이런지 궁금합니다!감사합니다.
-
해결됨Do it! 알고리즘 코딩테스트 with C++
백준 1722 교재 81 질문
해당 문제를 푸는 알고리즘에 대해 더 자세한 설명이 필요할 것 같습니다.K번째 순열 출력할때, 왜 k와 (n-1)!를 비교하는지 이해가되지 않습니다.