일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- BFS
- DP
- dropout
- 가끔은 말로
- back propagation
- 너비 우선 탐색
- 플로이드 와샬
- 우선 순위 큐
- 이분 탐색
- dfs
- 백트래킹
- 가끔은_말로
- 조합론
- c++
- tensorflow
- 2023
- pytorch
- 회고록
- NEXT
- 알고리즘
- object detection
- Overfitting
- 크루스칼
- 다익스트라
- 자바스크립트
- lazy propagation
- 분할 정복
- 문자열
- 미래는_현재와_과거로
- 세그먼트 트리
- Today
- Total
Doby's Lab
[알고리즘] 백준 6443번: 애너그램 (C++), 백트래킹 중복 처리 유형 2번째! 본문
https://www.acmicpc.net/problem/6443
6443번: 애너그램
첫째 줄에 단어의 개수 N 이, 둘째 줄부터 N개의 영단어가 들어온다. 영단어는 소문자로 이루어져 있다. 단어의 길이는 20보다 작거나 같고, 애너그램의 수가 100,000개 이하인 단어만 입력으로 주
www.acmicpc.net
단순한 백트래킹 문제인 줄 알았으나 꽤 조건이 까다로운 문제다.
허나, 이 조건은 예전에 N과 M 시리즈를 풀 때도 한 번 크게 겪었던 똑같은 유형이었다.
(N과 M (9) 문제: https://www.acmicpc.net/problem/15663)
(N과 M (9) 포스팅: https://draw-code-boy.tistory.com/29)
이 문제에서 필요한 건 정렬과 이전 노드(같은 depth)에 대한 기억
정렬이 필요한 이유는 예를 들어 acba라는 문자열이 주어졌을 때의 애너그램을 구한다고 하면
정렬이 되지 않으면 처음에 등장하는 a라는 노드에 대한 기억을 c로 넘어가면서 지워져 버리기 때문이다.
>> 정렬을 통해 같은 노드끼리 묶어두려는 방법이다.
예전에는 이 문제를 이해하느라 엄청 어려웠었는데 쉽게 이해할 수 있는 방법(?)을 찾은 거 같다.
백트래킹을 통해 발생하는 재귀의 횟수를 depth라고 했을 때, 같은 depth에 같은 노드가 있다는 건 똑같은 문자열이 구해진다는 것과 같다.
그래서 아래에 before이라는 기억을 하는 변수는 모두 같은 depth에 해당이 되는 노드들 간에 관계성을 구하는 변수이다.
void backTrack(string value, int cnt, string ret) {
if (cnt == value.size()) {
cout << ret << '\n';
return;
}
char before = '!';
for (int i = 0; i < value.size(); i++) {
if (!visited[i] && value[i] != before) {
visited[i] = 1;
before = value[i];
backTrack(value, cnt + 1, ret + value[i]);
visited[i] = 0;
}
}
}
N과 M (9)를 안 풀어본 사람들이 이 문제가 어렵다고 느껴질 수 있는 이유는 기존의 백트래킹에서는 항상 재귀의 조건(세로)만 따졌다면 이 문제에서는 같은 depth의 노드들끼리의 관계(가로)도 신경 써야 하기 때문이다.
(가로와 세로는 그저 이해를 돕기 위한 말)
(물론 재귀의 조건에서 가로도 따진다.)
[AC 코드]
#include <iostream>
#include <algorithm>
using namespace std;
int T;
bool visited[20] = { 0, };
void backTrack(string value, int cnt, string ret) {
if (cnt == value.size()) {
cout << ret << '\n';
return;
}
char before = '!';
for (int i = 0; i < value.size(); i++) {
if (!visited[i] && value[i] != before) {
visited[i] = 1;
before = value[i];
backTrack(value, cnt + 1, ret + value[i]);
visited[i] = 0;
}
}
}
int main() {
cin >> T;
for (int t = 0; t < T; t++) {
string value;
cin >> value;
sort(value.begin(), value.end());
string ret = "";
backTrack(value, 0, ret);
}
return 0;
}
공부한 거 써먹었다 ㅎㅎ
'PS > BOJ' 카테고리의 다른 글
[알고리즘] 백준 11725번: 트리의 부모 찾기 (C++), 2차원 동적 배열 (vector) (0) | 2021.11.17 |
---|---|
[알고리즘] 백준 11561번: 징검다리 (C++), 등차수열의 합, 이젠 수학까지 해야 하니 (0) | 2021.11.15 |
[알고리즘] 백준 3020번: 개똥벌레 (C++), 다시 한 번 틀을 깨다 (0) | 2021.11.15 |
[알고리즘] 백준 16953번: A → B (C++), 당신 1억 맞죠? 아뇨 사람 잘못 보셨는데요 (0) | 2021.11.14 |
[알고리즘] 백준 14002번: 가장 긴 증가하는 부분 수열 4 (C++), 앞으로는 temp를 잘 활용해보자 (0) | 2021.11.14 |