Search

순열 알고리즘, DFS 그래프 경로찾기, 가중치 그래프 탐색

순열 알고리즘

네장의 카드를 모두 이용하여 숫자를 출력하고자 한다.
중복을 허용하지 않는 순열을 처리하는 방법
순열 알고리즘 규칙 1
재귀호출을 돌리지 않고, 다음과 같은 규칙으로 구할 수 있다.
1.
맨 오른쪽 부터 숫자부터 2개씩 비교한다.
2.
왼쪽보다 오른쪽 숫자가 더 큰 index를 찾아서 빨간색으로 체크한다.
3.
예를 들어서 1 6 5 3 이라면 1 6 5 3
4.
예를 들어서 5 6 17 이라면 5 6 1 7
5.
예를 들어서 7 8 1 1 이라면 7 8 1 1
이렇게 찾은 index를 a라고 하자.
순열 알고리즘 규칙 2
1.
다시 맨 오른 쪽 숫자부터 a까지 숫자를 찾자.
2.
[a]보다 더 큰 숫자를 발견하면 파란색으로 표시하자
3.
빨간색과 파란색 index값을 찾아내서 swap해주자
4.
예를 들어서 1 6 5 3 이라면 1 6 5 3 : 3 6 5 1
5.
예를 들어서 5 6 17 이라면 5 6 1 7 : 5 6 7 1
6.
예를 들어서 7 8 1 1 이라면 7 8 1 1 : 8 7 1 1
순열 알고리즘 규칙3
1.
a index 다음 숫자부터 맨 끝까지 숫자를 전부 뒤집음
2.
만약에 a뒤에 숫자가 3개있으면 3개다 뒤집음
3.
예를 들어서 1 6 5 3 이라면 1 6 5 3 : 3 6 5 1 → 3 1 5 6
4.
예를 들어서 5 6 17 이라면 5 6 1 7 : 5 6 7 1 → 5 6 7 1
5.
예를 들어서 7 8 1 1 이라면 7 8 1 1 : 8 7 1 1 → 8 1 1 7
#include <iostream> char history[5] = ""; char cards[5] = "1234"; int visited[10] = { }; void dfs(int level) { if (level == 4) { std::cout << history << std::endl; return; } for (int i = 0; i < 4; i++) { if (visited[i] == 0) { history[level] = cards[i]; visited[i] = 1; dfs(level + 1); visited[i] = 0; history[level] = 0; } } } // 재귀함수를 쓰지않고 모든 순열을 출력하는 소스코드 int nextPermutation(int* data, int n) { // 오른쪽 왼쪽으로 a찾기 (index) int i = n - 1; while (i > 0 && data[i - 1] >= data[i]) i -= 1; if (i <= 0) return 0; // 오른쪽에서 왼쪽으로 b찾기 (index) int j = n - 1; while (data[j] <= data[i - 1]) j -= 1; // swap data[i-1] and data[j] int temp = data[i - 1]; data[i - 1] = data[j]; data[j] = temp; //a값 이후의 위치부터 전부 뒤집기 j = n - 1; while (i < j) { temp = data[i]; data[i] = data[j]; data[j] = temp; i += 1; j -= 1; } return 1; } int main() { dfs(0); std::cout << "===========nextPermutation===========" << std::endl; int data[4] = { 1,2,3,4 }; int x; int n = 4; int result; while (true) { for (x = 0; x< 4; x++) { std::cout << data[x]; } std::cout << std::endl; result = nextPermutation(data, n); if (result == 0) break; } return 0; }
JavaScript
복사

그래프 DFS

DFS 그래프 경로찾기
A에서 D로가는 경로 총 네가지 경로가 있다.
A-B-D
A-B-C-D
A-C-D
A-C-B-D
기존 TREE DFS와 크게 다르지 않다.
프로토 타입 void dfs(int level, int now)
return 조건이 name[now] == ‘D’ 리턴
그래프니까 사이클생길수 있다. 무한재귀가 발생하지 않도록
싸이클 중복여부를 체크해줘야한다.
#include <iostream> char name[5] = "ABCD"; int data[4][4] = { 0,1,1,0, 1,0,1,1, 1,1,0,1, 0,1,1,0, }; char history[5] = ""; int count = 0; int IsPossible(int level, int select) { for (int i = 0; i < level; i++) { if (history[i] == name[select]) { return 0; } } return 1; } void dfs(int level, int now) { if (name[now] == 'D') { count++; std::cout << history << std::endl; return; } for (int i = 0; i < 4; i++) { if (data[now][i] == 1) { if (IsPossible(level, i) == 1) { history[level + 1] = name[i]; dfs(level + 1, i); history[level + 1] = 0; } } } } int main() { history[0] = name[0]; dfs(0, 0); return 0; }
JavaScript
복사

가중치 있는 그래프 탐색

A에서 D까지 가는 최소비용 Rounte찾는다.
인접행렬에서 0과 1대신에 가중치값을 넣어주고
전달인자에 sum 변수를 추가하여 누적합을 계산해준다.
진입할때 sum을더하고 다음 시점으로 이동한다.
#include <iostream> char name[5] = "ABCD"; int data[4][4] = { 0,10,60,0, 10,0,20,40, 60,20,0,50, 0,40,50,0, }; char history[5] = ""; int count = 0; int IsPossible(int level, int select) { for (int i = 0; i < level; i++) { if (history[i] == name[select]) { return 0; } } return 1; } void dfs(int level, int now, int sum) { if (name[now] == 'D') { count++; std::cout << history << std::endl; return; } for (int i = 0; i < 4; i++) { if (data[now][i] > 1) { if (IsPossible(level, i) == 1) { history[level + 1] = name[i]; dfs(level + 1, i, sum + data[now][i]); history[level + 1] = 0; } } } } int main() { history[0] = name[0]; dfs(0, 0, 0); return 0; }
JavaScript
복사