funsolve(initialState:State):List<Solution>{// 탐색을 하며 찾은 정답을 저장할 저장소valsolutions=mutableListOf<Solution>()backtrack(initialState,solutions)returnsolutions}funbacktrack(// 현재 상태currentState:state,// 탐색을 하며 찾은 정답을 저장할 저장소solutions:MutableList<Solution>){// 1. 종료 조건 (Base Case)// 현재 상태가 문제의 해답이라면if(isSolution(currentState)){solutions.add(currentState.toSolution())return}// 2. 재귀 호출 (Recursive Step)// 현재 상태에서 다음으로 진행 가능한 모든 상태들을 탐색for(stateingetNextStates(currentState)){// 상태 확인 (가지치기)if(isPromising(state)){// 상태 변환 (전이)...// 탐색 진행backtrack(state,solutions)// 백트랙// 함수 호출 스택에서 이전 상태로 돌아가는 백트랙은 재귀 호출이 끝난 후 자동으로 이루어진다.// 상태 되돌리기// 하나의 경로 탐색이 끝난 후에 다른 경로를 탐색할 수 있도록 상태를 이전 상태로 명시적으로 되돌려야 하는 경우 이 곳에서 수행한다....}}}// 현재 상태가 문제의 해답인지 확인funisSolution(state:state):Boolean{// 문제의 종료 조건 판별 로직...}// 현재 상태에서 다음으로 진행 가능한 모든 상태를 조회fungetNextStates(state:state):List<state>{// 다음으로 진행할 수 있는 모든 경우의 수를 조회...}// 상태가 적합한지 확인funisPromising(state:state):Boolean{// 제약 조건 만족 검사 로직 구현...}
N-퀸 문제
classSolution{privatevarcount=0funnQueens(n:Int):Int{// 퀸이 위치한 열 번호를 저장할 배열valboard=IntArray(n){0}backtrack(n,0,board)returncount}funbacktrack(// 현재 상태n:Int,row:Int,// 탐색을 하며 찾은 정답을 저장할 저장소board:IntArray){// 1. 종료 조건// 모든 퀸을 성공적으로 배치한 경우if(row==n){count++return}// 2. 재귀 호출// 현재 행(row)에 퀸을 놓을 수 있는 모든 열(col)을 탐색for(colin0untiln){// 상태 확인 (가지치기)// 현재 위치(row, col)에 퀸을 놓을 수 있는지 확인if(isPromising(row,col,board)){// 상태 변환 (전이)// 퀸을 배치board[row]=col// 탐색 진행// 다음 행으로 이동backtrack(n,row+1,board)// 백트랙// 상태를 덮어쓰는 방식이므로, 상태 되돌리기 과정은 별도로 필요하지 않다.}}}// 현재 위치(row, col)에 퀸을 놓을 수 있는지 확인funisPromising(row:Int,col:Int,board:IntArray):Boolean{// 같은 열에 퀸이 있는지, 대각선에 퀸이 있는지 확인for(iin0untilrow){// 같은 열에 퀸이 있는지 (board[i] == col)// 또는 대각선에 퀸이 있는지 (abs(row - i) == abs(col - board[i]))if(board[i]==col||(row-i)==Math.abs(col-board[i])){returnfalse}}returntrue}}funmain(){valsolution=Solution()valn=4valresult=solution.nQueens(n)println(result)}
순열 문제
classsolution {
fun permutations(n: Int,m:Int):List<List<Int>>{valresults=mutableListOf<List<Int>>()valcurrentPermutation=mutableListOf<Int>()// 1부터 n까지의 숫자 사용 여부를 저장할 배열valused=BooleanArray(n+1){false}backtrack(n,m,currentPermutation,used,results)returnresults}funbacktrack(// 현재 상태n:Int,m:Int,currentPermutation:MutableList<Int>,used:BooleanArray,// 탐색을 하며 찾은 정답을 저장할 저장소results:MutableList<List<Int>>){// 1. 종료 조건// 현재 순열의 길이가 m과 같을 경우if(currentPermutation.size==m){results.add(ArrayList(currentPermutation))return}// 2. 재귀 호출// 1부터 n까지의 모든 숫자를 탐색for(iin1..n){// 상태 확인 (가지치기)// 현재 숫자를 사용할 수 있는지 확인if(isPromising(i,used)){// 상태 변환 (전이)currentPermutation.add(i)used[i]=true// 탐색 진행backtrack(n,m,currentPermutation,used,results)// 백트랙// 상태 되돌리기currentPermutation.removeAt(currentPermutation.size-1)used[i]=false}}}// 현재 숫자를 사용할 수 있는지 확인funisPromising(i:Int,used:BooleanArray):Boolean{// 이미 사용한 숫자인지 확인if(used[i]){returnfalse}returntrue}}funmain(){valn=3// 1부터 3까지의 자연수valm=2// 2개를 선택valsolution=solution()valresult=solution.permutations(n,m)result.forEach{println(it.joinToString(" "))// 각 순열 출력}}
classSolution{funletterCombinations(digits:String):List<String>{vallettersArray=arrayListOf("","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz")valresult=mutableListOf<String>()valinitialState=StringBuilder()if(digits.isEmpty()){returnemptyList()}funbacktrack(// 현재 상태digits:String,index:Int,currentState:StringBuilder,// 탐색을 하며 찾은 정답을 저장할 저장소result:MutableList<String>){// 1. 종료 조건// 모든 자릿수에 대해 처리한 경우if(index==digits.length){valterminalState=currentState.toString()result.add(terminalState)return}valdigit=Character.getNumericValue(digits[index])valletters=lettersArray[digit]// 2. 재귀 호출// 해당 자릿수의 모든 문자를 탐색for(iinletters.indices){// 상태 확인 (가지치기)valletter=letters[i]currentState.append(letter)// 탐색 진행backtrack(digits,index+1,currentState,result)// 백트랙// 상태 되돌리기currentState.deleteCharAt(currentState.length-1)}}backtrack(digits,0,initialState,result)returnresult}}funmain(){valsolution=solution()valresult=solution.letterCombinations("23")println(result)}
문자열은 연속된 문자들이 그룹화되어 구성된 자료 구조이다. 따라서 데이터를 그룹화한 추상 자료형인 컬렉션(collection)의 다양한 자료 구조로 문자열을 구조화할 수 있으며 다양한 자료 구조 탐색 알고리즘을 사용하여 부분 문자열들을 탐색 및 비교하는 등의 문제를 해결할 수 있다.
백트래킹(backtracking)(또는 역추적) 알고리즘이란 최적의 해결책을 찾기 위해 모든 가능한 방법을 후보(candidate)로 구성한 후, 점진적으로 후보들을 시도하면서 유효한 후보가 아닐 경우(문제의 정답 조건을 만족하지 않을 경우) 문제 해결 과정에서 제외하고 되돌아가 ...
Comments