https://www.youtube.com/watch?v=Enz2csssTCs&t=3s
해를 찾는 도중 해가 아니어서 막히면, 되돌아가서 다시 해를 찾아가는 기법
dfs와의 차이점: dfs는 모두 탐색. backtracking은 막히면 더 깊이 들어가지 않고 이전 단계로 돌아감 비슷한데 다름
헤더: <algorithm>
template <class BidirectionalIterator> bool next_permutation (BidirectionalIterator first, BidirectionalIterator last);
순열을 만들어주는 함수.
https://twpower.github.io/82-next_permutation-and-prev_permutation
전체 n개의 원소들 중에서 k개를 뽑는 조합(=nCk)을 구한다면 n개의 벡터 원소에 1을 k개 0을 나머지인 n-k개 집어넣어서 순열을 돌리고 1에 해당하는 인덱스만 가져오면 된다.
이 때 0 0 .. 1 1 .. 이런식의 꼴로 시작해야함!! next_permutation 순서가 0 0 .. 1 1 .. 로 시작해서 1 1 .. 0 0 .. 으로 끝남
https://twpower.github.io/82-next_permutation-and-prev_permutation
이유: next_permutation은 중복이 있는 원소의 경우 중복인 경우를 제외
하고 순열을 만들어 준다.
0 0 1 1
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0
대충 흐름을 보면 n개의 원소중 1에 해당하는 인덱스가 조합에 포함된다고 보면 되는 것을 알 수 있음
https://github.com/encrypted-def/basic-algo-lecture/blob/master/workbook/0x0C.md
visited를 어떻게 활용해야 할지를 잘 생각해보면 된다
재귀 함수 들어가기 전에 내 노드를 visited 표시하고, 재귀함수를 나오면 내 노드가 visited인 상태에서 탐색이 다 끝난 거니까 다시 visited를 false로 바꿔줌
n퀸 문제. 백트래킹이라 15649랑 비슷하게 풀면 됨. 대신 이번에 visited를 내 열에 해당하는 것, 내 왼쪽 대각선에 해당하는 것, 오른쪽 대각선에 해당하는 것 세 개를 써야 함.
재귀를 타고가는 아이디어: arr[i]번 째를 포함하는 부분집합으로 갈 건가, 포함하지 않는 부분집합으로 갈 건가.
void f(int k, int total) {
if (k == N) return;
if (total + arr[k] == S) ++ans;
f(k + 1, total);
f(k + 1, total + arr[k]);
}
중복인 경우를 제외하고 수열을 만들어줘야 함.
함수 인자에 시작 인덱스를 넘겨주면 됨.
그럼 이번에 나간 인덱스 다음에 있는 원소들로 수열을 만들어주기 때문.
void p(int idx, int k) {
if (k == M) {
for (int i = 0; i < k; ++i) cout << arr[i] << ' ';
cout << '\n';
return;
}
for (int i = idx; i < N; ++i) {
if (vis[i]) continue;
arr[k] = i + 1;
vis[i] = 1;
p(i + 1, k + 1);
vis[i] = 0;
}
}
방법2. next_permutation 사용.
int main(void) {
cin >> N >> M;
for (int i = M; i < N; ++i) arr[i] = 1;
do {
for (int i = 0; i < N; ++i) {
if (!arr[i]) cout << i + 1 << ' ';
}
cout << '\n';
} while(next_permutation(arr, arr + N));
}
이번엔 같은 수를 여러 번 골라도 되기 때문에 vis배열이 필요가 없음
비내림차순을 만족해야 하기 때문에
if (k > 0 && arr[k - 1] > i + 1) continue;
조건을 추가해줌
sort 함수 사용하기. arr[k] = i + 1
대신 ans[k] = arr[i];
시작 인덱스를 함수 인자로 넘겨주면 됨
15651과 똑같음
처음 배열 받을 때 중복 없이 받아줬음 그리고 비내림차순이니까 시작 위치 함수 인자로 넘겨주면 됨
간단한 문제 시작 인덱스 넘겨주면 됨
조건 잘 살피기! aeiou가 하나 이상 있어야 하고 자음이 2개 이상 있어야 함
#include <iostream>
#include <algorithm>
using namespace std;
int L, C, cnt;
char arr[26], ans[26];
bool is_vowel(char c) {
return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u');
}
void dfs(int k, int st) {
if (k == L) {
if (cnt < 1) return; // 모음이 하나도 없는 경우였다면 그냥 리턴
for (int i = 0; i < k; ++i) cout << ans[i];
cout << '\n';
return;
}
for (int i = st; i < C; ++i) {
if (is_vowel(arr[i])) {
if (L - (cnt + 1) < 2) continue; // 이번에 모음을 추가했을 때 자음이 2개 미만이 되는 거면 그냥 contiue
++cnt; // 그게 아니라면 모음이 추가될 것이므로 ++cnt
}
ans[k] = arr[i];
dfs(k + 1, i + 1);
if (is_vowel(arr[i])) --cnt; // 모음이 추가됐을 때 상황을 다 돌고 나온 것이기 때문에 다시 --cnt
}
}
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> L >> C;
for (int i = 0; i < C; ++i) cin >> arr[i];
sort(arr, arr + C);
dfs(0, 0);
}
와.......... 걍 진작 답 볼걸
이건 dfs랑 bfs를 같이 써야 하는 문제.
그새 또 bfs 하는 법 까먹어서 헤맸다;; 역시 복습만이 살 길..
전체 개요
1. dfs로 25C7을 구한다. 25자리 중 7자리를 뽑는 것.
2. 뽑은 자리에 S파가 4명 이상이고
3. bfs로 구한 너비가 7이면 ++ans
dfs를 할 때 뽑힌 자리를 체크해준다. bfs를 하기 위해서!!
조합으로 뽑힌 자리만 1로 채워준 combi7[5][5] 배열을 만들어준다.
그래야 bfs를 할 때 1인 부분만(조합으로 뽑힌 자리만) 탐색해 나갈 수 있으니까
#include <iostream>
#include <queue>
#include <tuple>
using namespace std;
#define X first
#define Y second
char board[5][5];
int arr[7], combi7[5][5], ans;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, -1, 0, 1};
int bfs(int r, int c) {
queue<pair<int, int> > q;
bool vis[5][5] = {};
int cnt = 0;
q.push(pair(r, c));
vis[r][c] = 1;
while (!q.empty()) {
int x, y;
tie(x, y) = q.front(); q.pop();
++cnt;
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || nx >= 5 || ny < 0 || ny >= 5) continue;
if (vis[nx][ny] || !combi7[nx][ny]) continue;
vis[nx][ny] = 1;
q.push({nx, ny});
}
}
return cnt;
}
void dfs(int k, int st, int dasom) {
if (k == 7) {
if (dasom >= 4 && bfs(arr[0] / 5, arr[0] % 5) == 7) ++ans;
return;
}
for (int i = st; i < 25; ++i) {
arr[k] = i;
combi7[i / 5][i % 5] = 1; // bfs를 하기 위해 뽑힌 자리를 체크해준다.
dfs(k + 1, i + 1, dasom + (board[i / 5][i % 5] == 'S'));
combi7[i / 5][i % 5] = 0; // dfs를 돌고 나온 후니까 다시 0으로 바꿔줌.
}
}
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0);
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) cin >> board[i][j];
}
dfs(0, 0, 0);
cout << ans;
}