PS/PS Log
23.08.16. 풀었던 문제들 복기
hyelie
2023. 8. 16. 18:58
9646. 다이어그램과 태블로, 2시간
딱 보면 backtracking + purning으로 푸는 문제.
일단 아래로 내릴 수 있으면 내리고, 너무 많이 내려간 경우 다음 col로 넘어가는 형식으로 구현했다.
그러면 backtracking의 종료조건은 마지막 col을 탐색하고, 다음 칸을 탐색할 때 answer++를 해 주면 된다.
다음으로, backtracking 과정은
- 위/왼쪽에 있는 값을 보고 조건을 맞춘다.
- 여기서 하나 purning을 하는데, 아래 칸으로 내릴 수 있으면 바로 내리고, 그렇지 않으면 바로 다음 col을 탐색한다.
- 만약 이 과정을 recurse()에서 if문으로 걸면 call stack이 1번씩 더 쌓인다. worst case 모든 경우에 하나씩 더 쌓이게 되므로 이 과정을 여기로 뺀다.
- 이것만으로 충분했다.
int k, N, num_col[8], board[8][8], answer;
// num_col[i] : i번째 row의 col 개수
// recurse(row, col) - row, col에서 backtrack
void recurse(int row, int col){
// top-down recurse 종료조건
if(row == 0 && num_col[row] <= col){
answer++;
return;
}
// 위/왼쪽 보고 가능한 숫자부터 recurse. 세로부터 채움.
int s = 1;
if(row > 0) s = max(s, board[row-1][col] + 1); // 위
if(col > 0) s = max(s, board[row][col-1]); // 왼
for(int i = s; i<=N; i++){
board[row][col] = i;
if(num_col[row+1] > col){ // 아래칸으로 내릴 수 있으면 내리고, 그렇지 않으면 바로 다음 col로 감.
recurse(row+1, col);
}
else{
recurse(0, col+1);
}
}
}
void solve(){
while(1){
cin>>k;
if(cin.eof()) return;
for(int i = 0; i<8; i++) num_col[i] = 0;
for(int i = 0; i<8; i++){
for(int j = 0; j<8; j++){
board[i][j] = 0;
}
}
for(int i = 0; i<k; i++) cin>>num_col[i];
cin>>N;
answer = 0;
recurse(0, 0);
cout<<answer<<"\n";
}
}
//////////////////////
int main(void) {
cin.tie(0);
cout.tie(0);
std::ios_base::sync_with_stdio(0);
solve();
return 0;
}
후기
이런 purning 문제는 너무 빡세다.