방향 그래프의 1번 정점에서 n번 정점으로 가는 모든 경로의 가지 수를 출력하시오.
첫 줄은 정점 , 간선 수
5 9
1 2
1 3
1 4
2 1
2 3
2 5
3 4
4 2
4 5
1 2 3 4 5
1 2 5
1 3 4 2 5
1 3 4 5
1 4 2 5
1 4 5
무방향 그래프 - graph[a][b] = 1 / graph[b][a] = 1
방향 그래프 - graph[a][b] = 1
가중치 방향 그래프 - graph[a][b] = c
정점 갯수가 많아지면 인접행렬은 메모리 낭비와 시간 복잡도가 길어진다.
그때 인접리스트 사용하면 된다. 현재는 인접행렬로 연습.
인접행렬은 N제곱 크기 만큼 배열로 만들어야 하므로 정점이 많아질 때 인접리스트를 사용하는게 좋다.
그리고 갈 수 있는 정점을 확인하는것도 N만큼 계속 돌아야한다..
정점이 10000개이면 10000 * 10000 만큼의 배열이 필요하고
해당 정점에서 10000개의 정점으로 갈 수 있는지 매번 확인해봐야 한다...
인접리스트는 처음부터 해당 정점에서 갈 수 있는 정점만 추가한 것이므로 성능상 매우 좋다.
각 정점에서 갈 수 있는 정점들을 넣어놨으므로 갈 수 있는지 확인할 필요가 없고
따라서 해당 정점이 방문한 노드인지 아닌지만 따지면 된다.
하지만 노드 1과 7이 연결되어 있는 경우 인접 행렬 방식은 graph[1][7]만 확인하면 되지만 인접 리스트 방식은 1에 대한 인접 리스트를 앞에서부터 차례대로 확인하게 되어 연결 정보를 얻는데에는 느리긴하다.
방문한 정점에 대해서 체크해주는 배열이 필요하다.
여기서 방문 처리의 이유는 경로가 무한으로 만들어질 수 있기 때문이다.
1->2->5 1->2->1->2->5 같은..
다른 경로도 탐색해봐야하기 때문에 경로가 만들어진 뒤 방문 체크를 풀어준다.
인자로는 시작 정점인 1을
매개변수로는 마지막 정점인 n으로 설정해주었음
import java.util.*;
public class Main {
static int n, m, answer = 0;
static int[][] graph;
static int[] ch; //방문여부 체크
public void DFS(int v) { //초깃값 v = 1
//n번(5번) 정점에 도착했으면 하나의 경로가 만들어짐
if(v == n) answer++;
//n번(5번) 정점이 아니고 n번을 향해 더 뻗어나가야하면
else {
//v번 노드에서 1번 노드부터 n번 노드까지 뻗어볼거임
for(int i = 1; i <= n; i++) {
//현재의 지점인 v번 정점에서 i번 정점으로 갈 수 있냐 && 방문 안했냐
if(graph[v][i] == 1 && ch[i] == 0) {
ch[i] = 1;
DFS(i);
//다른 정점들도 확인해봐야하므로 방문한 정점 미방문으로 체크
ch[i] = 0;
}
}
}
}
public static void main(String[] args) {
Main T = new Main();
Scanner kb = new Scanner(System.in);
n = kb.nextInt(); //노드의 갯수(정점의 갯수)
m = kb.nextInt(); //간선의 갯수
graph = new int [n+1][n+1]; //정점 번호
ch = new int[n+1];
//a에서 b로 간다는 의미.
for(int i = 0; i < m; i++) {
int a = kb.nextInt();
int b = kb.nextInt();
graph[a][b] = 1;
}
ch[1]=1;
T.DFS(1);
System.out.println(answer);
}
}
1번 정점에서 2,3,4번 정점 갈 수 있음
2번 정점에서 1,3,5번 정점 갈 수 있음
3번 정점에서 4번 정점 갈 수 있음
4번 정점에서 2,5번 정점 갈 수 있음
ch[1] = 1 / v = 1
D(1) - 먼저 2번 정점으로 가는 경우를 처리 (3,4번 남아있음)
1->2
ch[2] = 1 / D(2) 호출 17라인 멈춤
D(2) - 1번은 못가고 3번 정점으로 가는 경우를 처리 (5번 남아있음)
1->2->3
ch[3] = 1 / D(3) 호출 17라인 멈춤
D(3) - 4번 정점으로 가는 경우를 처리
1->2->3->4
ch[4] = 1; / D(4) 호출 17라인 멈춤
D(4) - 2번은 못가고 5번 정점으로 가는 경우를 처리
1->2->3->4->5
ch[5] = 1; / D(5) 호출 17라인 멈춤
v == 5 n == 5 / v == n 이므로 5번 정점 도착. 1->2->3->4->5로 갈 수 있음(answer = 1)
D(4)의 17라인 다시 돌아와서 ch[5] = 0로 만들고 끝
1->2->3->4
D(3)의 17라인 다시 돌아와서 ch[4] = 0로 만들고 끝
1->2->3
D(2)의 17라인 다시 돌아와서 ch[3] = 0로 만들고 5번 정점으로 가는 경우를 처리
1->2->5
ch[5] = 1; / D(5) 호출 17라인 멈춤
v == 5 n == 5 / v == n 이므로 5번 정점 도착. 1->2->5로 갈 수 있음(answer = 2)
D(2)의 17라인 다시 돌아와서 ch[5] = 0로 만들고 끝
1->2
D(1)의 17라인 다시 돌아와서 ch[2] = 0로 만들고 3번 정점으로 가는 경우를 처리(4번 남아있음)
1->3
ch[3] = 1; / D(3) 호출 17라인 멈춤
D(3) - 4번 정점으로 가는 경우를 처리
1->3->4
ch[4] = 1; / D(4) 호출 17라인 멈춤
D(4) - 2번 정점으로 가는 경우를 처리(5번 남아있음)
1->3->4->2
ch[2] = 1; / D(2) 호출 17라인 멈춤
D(2) - 1번은 못가고, 3번도 못가고 5번 정점으로 가는 경우를 처리
1->3->4->2->5
ch[5] = 1; / D(5) 호출 17라인 멈춤
v == 5 n == 5 / v == n 이므로 5번 정점 도착. 1->3->4->2->5로 갈 수 있음(answer = 3)
D(2)의 17라인으로 다시 돌아와서 ch[5] = 0로 만들고 끝
1->3->4->2
D(4)의 17라인으로 다시 돌아와서 ch[2] = 0로 만들고 5번 정점으로 가는 경우를 처리
1->3->4->5
ch[5] = 1; / D(5) 호출 17라인 멈춤
v == 5 n == 5 / v == n 이므로 5번 정점 도착. 1->3->4->5로 갈 수 있음(answer = 4)
D(4)의 17라인으로 다시 돌아와서 ch[5] = 0로 만들고 끝
1->3->4
D(3)의 17라인으로 다시 돌아와서 ch[4] = 0로 만들고 끝
1->3
D(1)의 17라인으로 다시 돌아와서 ch[3] = 0로 만들고 4번 정점으로 가는 경우를 처리
1->4
ch[4] = 1; D(4) 호출 17라인 멈춤
D(4) - 2번 정점으로 가는 경우를 처리(5번 남아있음)
1->4->2
ch[2] = 1; / D(2) 호출 17라인 멈춤
D(2) - 1번으로는 못가고 3번 정점으로 가는 경우를 처리(5번 남아있음)
1->4->2->3
ch[3] = 1; D(3) 호출 17라인 멈춤
D(3) - 4번 정점으로 못가고 갈 수 있는 곳이 없음
D(2)의 17라인으로 돌아와서 ch[3] = 0으로 만들고 5번 정점으로 가는 경우를 처리
1->4->2->5
ch[5] = 1; / D(5) 호출 17라인 멈춤
v == 5 n == 5 / v == n 이므로 5번 정점 도착. 1->4->2->5로 갈 수 있음(answer = 5)
D(2)의 17라인으로 돌아와서 ch[5] = 0으로 만들고 끝
1->4->2
D(4)의 17라인으로 돌아와서 ch[2] = 0으로 만들고 5번 정점으로 가는 경우를 처리
1->4->5
ch[5] =1; / D(5) 호출 17라인 멈춤
v == 5 n == 5 / v == n 이므로 5번 정점 도착. 1->4->5로 갈 수 있음(answer = 6)
'Algorithm > inflearn' 카테고리의 다른 글
★그래프 최단거리(BFS) (0) | 2021.09.30 |
---|---|
★경로 탐색(인접리스트) (0) | 2021.09.30 |
Tree 말단노드까지의 가장 짧은 경로(BFS) (0) | 2021.09.30 |
Tree 말단노드까지의 가장 짧은 경로(DFS) (0) | 2021.09.29 |
★송아지 찾기1(BFS) (0) | 2021.09.29 |