출퇴근길
문제 링크 : https://softeer.ai/practice/6248
접근 방식
인접 리스트에 출퇴근 경로를 저장한다.
출발지부터 도착지까지 이동하면서, 방문한 정점을 기록한다.
출퇴근길간의 정점을 비교해서, 중복되는 정정의 개수를 리턴한다.
잘못된 접근
import java.io.*;
import java.util.*;
public class Main {
static LinkedList<Integer>[] list;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int result = 0;
int n = sc.nextInt(); // 정점 수
int m = sc.nextInt(); // 간선 수
list = new LinkedList[n+1];
for(int i=1; i<=n; i++){
list[i] = new LinkedList();
}
for(int i=0; i<m; i++){
int start = sc.nextInt();
int end = sc.nextInt();
list[start].add(end);
}
int S = sc.nextInt(); // 집의 정점 번호
int T = sc.nextInt(); // 회사의 정점 번호
boolean visited1[] = new boolean[n+1];
boolean visited2[] = new boolean[n+1];
dfs(S, T, visited1);
dfs(T, S, visited2);
for(int i=1; i<=n; i++){
if(i!=S && i!=T && visited1[i] && visited2[i]) result++;
}
System.out.println(result);
}
private static void dfs(int start, int end, boolean[] visited) {
if(visited[start]) return;
visited[start] = true;
if(start==end) return;
for(int i:list[start]){
dfs(i, end, visited);
}
}
}
일부 상황에서, 오답이 발생했다.
디테일한 점이 부족했다.
나는 집에서 회사로 가는 모든 방식을 알고자했다.
하지만, 코드는 모든 방식이 아니라 일부 상황만을 고려한 코드였다.
현재 내 코드는, start부터 end까지 가면서 방문처리를 한다.
여기서 두 가지 기저조건을 통해 재귀를 탈출하고 있다.
하나는, 이미 방문했던 곳이라면 가지 않기
두번째는, 도착지라면 돌아가기
여기서 중요한 점은 갈 수 있는 경로만 찾을 수 있다는 것이다.
현재 문제는 도착지를 제외한 중복 방문을 허용하고 있다. 따라서 원래 코드에서는 이미 방문한 노드의 경우 방문처리를 통해 더 이상 방문하지 않기 때문에 어떻게든 도착지에 도착하는 경우는 포함하고 있지 않다.
따라서, 특정 노드에서 출발지 혹은 도착지에 갈 수 있는지 여부가 중요한 것이다.
그래서 역방향 그래프를 떠 올릴 수 있는지가 이 문제에서 중요한 쟁점이다.
결과
소스 코드
import java.io.*;
import java.util.*;
public class Main {
static LinkedList<Integer>[] list;
static LinkedList<Integer>[] rlist;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int result = 0;
int n = sc.nextInt(); // 정점 수
int m = sc.nextInt(); // 간선 수
list = new LinkedList[n+1];
rlist = new LinkedList[n+1];
for(int i=1; i<=n; i++){
list[i] = new LinkedList();
rlist[i] = new LinkedList();
}
for(int i=0; i<m; i++){
int start = sc.nextInt();
int end = sc.nextInt();
list[start].add(end);
rlist[end].add(start);
}
int S = sc.nextInt(); // 집의 정점 번호
int T = sc.nextInt(); // 회사의 정점 번호
boolean visited1[] = new boolean[n+1];
boolean visited2[] = new boolean[n+1];
boolean visited3[] = new boolean[n+1];
boolean visited4[] = new boolean[n+1];
dfs(S, T, visited1);
dfs(T, S, visited2);
rdfs(S, visited3);
rdfs(T, visited4);
for(int i=1; i<=n; i++){
if(i!=S && i!=T && visited1[i] && visited2[i] && visited3[i] && visited4[i]) result++;
}
System.out.println(result);
}
private static void dfs(int start, int end, boolean[] visited) {
if(visited[start]) return;
visited[start] = true;
if(start==end) return;
for(int i:list[start]){
dfs(i, end, visited);
}
}
private static void rdfs(int start, boolean[] visited) {
if(visited[start]) return;
visited[start] = true;
for(int i:rlist[start]){
rdfs(i, visited);
}
}
}
알게 된 점
그래프간의 정점과 간선을 인접 리스트로 표현할 때
특정 좌표까지의 도달 가능성을 생각해야하는 경우에는
역방향 그래프를 통해 모든 경우의 수를 생각할 수 있음을 알게되었다.