알고리즘/BAEKJOON
백준 16771번 Back and Forth
pureworld
2019. 4. 1. 17:46
백준 16771번 Back and Forth
백트래킹을 사용하여 푸는 문제이지만 시간복잡도가 충분하여, 완전탐색으로 풀 수 도 있다.
1. 완전탐색을 사용하여 푸는 방법
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #include <iostream> #include <string> #include<queue> #include <vector> #include <algorithm> #include<cmath> using namespace std; int BarnA[3001]; int visited[12]; int Count; vector<int> newKey; //2일 동안 첫번째 헛간에서 보유 할 수 있는 우유의 양 세기,중복은 세지않음 void Check(vector<int> A, vector<int> B,int val) { for (int i = 0; i <= 9; i++) { for (int j = 0; j <= 9; j++) { int num = B[i] - A[j]; if (!visited[val + num]) { visited[val+ num] = 1; Count++; } } } } int main() { ios_base::sync_with_stdio(0); cin.tie(0); vector<int> BucketA(10, 0); vector<int> BucketB(10, 0); for (int i = 0; i <= 9; i++) cin >> BucketA[i]; for (int i = 0; i <= 9; i++) { cin >> BucketB[i]; } visited[1000] = 1; //2일동안 교환할수 있는 모든 바가지의 경우*2일지난뒤 최종보유하는 우유의 양 세기 for (int i = 0; i <= 9; i++) { for (int j = 0; j <= 9; j++) { if (BucketB[j] != BucketA[i]) { int value = BucketB[j] - BucketA[i]; swap(BucketB[j], BucketA[i]); Check(BucketA, BucketB,1000+value); swap(BucketB[j], BucketA[i]); } } } cout << Count+1; return 0; } | cs |
보시다시피 for문이 4중첩까지 가버린다.... 당연히 백트래킹을 사용하는 코드가 훨씬 빠르다는 것을 알 수 있다.
2.백트래킹을 사용하는경우
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include <iostream> #include <string> #include<queue> #include <vector> #include <algorithm> #include<cmath> using namespace std; int Bucket[2][10]; bool used[2][10]; vector<int> ret; void CountBarn(int day, int sum) { if (day == 4 ) { ret.push_back(sum); return; } //같은 바스켓으로 왕복하는 경우 2일소비 if (day + 2 <= 4) CountBarn(day + 2, sum); //day가 짝수면 우유가 줄어들 차례,홀수면 늘어날 차례 int k = day & 1; for (int i = 0; i < 10; i++) if (used[k][i]==0) { used[k][i] = true; CountBarn(day + 1, sum + Bucket[k][i] * (k ? 1 : -1)); used[k][i] = false; } } int main() { ios_base::sync_with_stdio(0); cin.tie(0); for (int i = 0; i < 2; i++) for (int j = 0; j < 10; j++) cin >> Bucket[i][j]; CountBarn(0, 0); //중복 sort(ret.begin(), ret.end()); ret.erase(unique(ret.begin(), ret.end()), ret.end()); cout << ret.size(); return 0; } | cs |
for문은 한번, sort함수를 사용해서 정렬시킨뒤 중복제거를 해준 후 카운트하면 쉽게 풀 수 있다.
아직 recursive개념에 대해서 헷갈리시는 분들은 1번방법을 사용해서 풀고 이해하는 것이 좀더 쉬울 수도 있을 것 같다.
그러나 2번방법으로 푸는 것이 알고리즘의 접근에는 더 좋은 방식이다.