다음 본 문제는 또 삼성 상반기 문제 였던 사다리 조작문제입니다. 15684 사다리 조작
전 이 문제 손도 못 댔었는데.. 그 이유가 방법을 모른다는 것이긴 하지만..! 감이 완전 안오던 문제였어요. 이제 와서 풀어보고 느낀 것이지만, 정말 기초적인 개념이 매우 중요한 문제 였던 것 같습니다.
이번 문제는 전에 풀었던 감시문제와 비슷하게 순열 조합 개념이 들어갑니다. 정말 당황 스럽게도… 답은 전수 조사 였습니다.
삼성은 약간 DFS, BFS랑 조합을 섞은 시뮬레이션같은 문제를 좋아하나 봅니다.ㅋㅋㅋ
vector<int> T; int arr[4] = {1,2,3,4}; vector<vector<int>> com; void swap(int *a, int *b ){ int tmp; tmp = *a; *a = *b; *b = tmp; } void combination(int n, int r){ if(r == 0){ com.push_back(T); return; }else if(n<r){ return; } else { //loop이 아님 T.push_back(arr[n-1]); combination(n-1, r-1); //n-1Cr-1: 현재 아이템을 선택한 경우 T.pop_back(); combination(n-1, r); //n-1Cr: 현재 아이템을 선택하지 않은 경우 } }먼저 조합코드를 살펴봅시다. 주석에도 써놨지만 이렇게 됩니다.
- n에 대해 숫자를 선택
- 해당 숫자를 조합 세트에 집어넣고 다른 숫자를 선택하기 위해 재귀 호출(combination(n-1,r-1))
- 해당 숫자를 선택하지 않으므로 조합 세트에서 뺀 후에 재귀 호출(combination(n-1,r))
이를 활용하면 문제를 바로 해결할 수 있습니다. 왜 일까요?
결국 사다리 맵을 순방 하면서 빈 공간에 하나하나 놓아 가면서 체크하면 된다는 것이죠. 코드가 매우 짧으니까 한번 봅시다.
#include <iostream> #include <algorithm> #include <cstdio> using namespace std; int N,M,H; int map[31][35]={0,}; int ans=-1; bool check() { for(int start=1; start<=N; start++) { int end = start; for(int x=1; x<=H; x++) { if(map[x][end]==1) end+=1; else if((end-1)>=1 && map[x][end-1]==1) end-=1; } if(end!=start) return false; } return true; }먼저 check 함수 부터 보면 그냥 1,2,3,4,5가 들어갔다 나와서 1,2,3,4,5인지 체크하는 함수입니다. 간단하네요!
void Find(int x, int r, int q) { if(ans!=-1) return; if(r==0) { if(check()) ans=q; return; } for(int i=x; i<=H; i++) { for(int j=1; j<=N-1; j++) { if(map[i][j]==0) { if((map[i][j-1]==0)&&(map[i][j+1]==0)) { map[i][j]=1; Find(i,r-1,q); map[i][j]=0; } } } } }다음은 주축이 되는 Find 함수입니다. 아까 위에서 조합 코드랑 비슷하죠? 다른점은 2중 for loop라는거? 코드는 이러합니다.
- x는 깊이 수, r은 선택 사다리 개수, q는 선택할 수 있는 사다리 개수
- 맵의 빈 공간을 하나 하나에 사다리를 집어넣으면서 체크하는데 사다리를 다 골랐다면 check 함수를 통해 제대로 되었는지 체크
처음엔 첫 줄인 if(ans!=-1) return;
를 넣지 않았는데, 저걸 넣은 이유는 답이 구해지면 실행 시간을 단축시키기 위해 중단 시키려고 집어넣었습니다.
int main() { int a,b; scanf("%d %d %d",&N,&M,&H); for(int i=0; i<M; i++) { scanf("%d %d",&a,&b); map[a][b]=1; } for(int r=0; r<=3; r++) { Find(1,r,r); if(ans!=-1) break; } cout<<ans<<endl; return 0; }다음은 Main 함수입니다. 간단하네요!! 우리는 사다리가 3개 이하일 때만 값을 출력하고, 그 이상은 -1을 출력하니까 사다리 개수가 0,1,2,3일 때 가능한지 체크만 하면 되겠네요!! 진짜 허무하게 간단 했던 풀이네요.. 제가 코딩 하면서 틀렸거나 어려웠던 부분인데 여러분도 자세하게 체크하고자 써보면 이러합니다.
- 사다리를 안 놓아도 되는 사항 체크 처음엔 사다리가 아예 없는 경우에만 예외 처리를 해서 답을 0으로 출력 시켰는데, 그런 경우엔 사다리가 있지만 놓지 않아도 되는 경우를 체크를 못 하더라구요. 그래서 그냥 0부터 체크하게 설계하였습니다.
- 시간 단축 체크 위에서도 말했지만, 일말의 수행 경우도 제외시켜서 시간을 단축시켜야 한다는 것!
- 전수 조사 알고리즘 코딩을 하다보면 전수 조사에 대해 매우매우 반감을 가지게 되는데, 두려움 없이 해봐야 한다는 점…!!!
모두 파이팅!’
'코딩 소양 > 알고리즘 문제' 카테고리의 다른 글
[백준 알고리즘] 15683번 감시 (0) | 2018.10.16 |
---|---|
[백준 알고리즘] 6593번 상범빌딩 (0) | 2018.09.30 |
[백준 알고리즘] 2178번 미로찾기 (0) | 2018.09.26 |
[CodeGround] 괄호 문제 (0) | 2018.09.21 |
핵심 친구 찾기 문제 (0) | 2018.09.20 |