https://www.acmicpc.net/problem/18352
코드설명
다익스트라(Dijkstra) 혹은 BFS(너비우선탐색) 를 통해 해결할 수 있는 문제입니다.
다익스트라(Dijkstra)를 활용하여 풀경우에는 시간초과가 납니다.
시간복잡도를 비교해보겠습니다.
다익스트라의 시간복잡도는 O(ELogV) 입니다.
E는 간선의 개수, V는 노드의 개수입니다.
문제에 주어진 조건은
- 노드의 개수는, 2 ≤ N ≤ 300,000개입니다.
- 간선의 개수는 1 ≤ M ≤ 1,000,000개 입니다.
시간복잡도는 O( 1,000,000 * Log ( 300,000 ) )
BFS의 시간복잡도는 O(E + V)의 시간복잡도를 가집니다.시간복잡도는 O( 300,000 + 1,000,000 ) 입니다.
그렇기에, BFS를 활용하여 진행합니다.
코드
BFS를 활용한코드입니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int N, M, K, X;
public static int[] arr;
public static int answer = 0;
public static ArrayList<ArrayList<Node>> graph = new ArrayList<ArrayList<Node>>();
public static boolean[] visited;
public static ArrayList<Integer> arrstr = new ArrayList<Integer>();
public static StringBuilder sb = new StringBuilder();
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
X = Integer.parseInt(st.nextToken());
visited = new boolean[N+1];
for(int i=0;i<=N;i++) {
graph.add(new ArrayList<Node>());
}
for(int i=0;i<M;i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
//a번 노드에서 b노드로 가는 비용이 1 입니다.
graph.get(a).add(new Node(b, 1));
}
BFS(X);
Collections.sort(arrstr);
if(arrstr.size() == 0) {
System.out.println("-1");
}else {
for(int i=0;i<arrstr.size();i++) {
System.out.println(arrstr.get(i));
}
// System.out.println(sb.toString());
}
}
public static void BFS(int start) {
Queue<Node> q = new LinkedList<>();
q.offer(new Node(start, 0));
visited[start] = true;
while(!q.isEmpty()) {
Node temp = q.poll();
if(temp.cnt == K) {
// sb.append(temp.nodeB).append("\n");
arrstr.add(temp.nodeB);
}else if(temp.cnt > K) {
return ;
}
for(int i=0;i<graph.get(temp.nodeB).size();i++) {
Node next = graph.get(temp.nodeB).get(i);
if(visited[next.nodeB]) continue;
visited[next.nodeB] = true;
q.offer(new Node(next.nodeB, temp.cnt + 1));
}
}
}
}
class Node {
int nodeB;
int cnt;
public Node(int nodeB, int cnt) {
this.nodeB = nodeB;
this.cnt = cnt;
}
}
정답코드 2입니다.
qSize를 조절해서 처리하는 코드입니다.
정답코드 1번이 더 로직이 줄어들어 구현하기에 편합니다. BFS상에서 애초에 너비우선탐색이기에 이동한 횟수를 같이 처리한다면 몇번째까지가 BFS인지 쉽게 알 수 있습니다.
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int N, M, S, P, K, A, B, X;
// static int answer = 0;
static int[][] matrix;
static ArrayList<Integer> answer = new ArrayList<Integer>();
static ArrayList<Integer>[] arr;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
X = Integer.parseInt(st.nextToken());
arr = new ArrayList[N];
for(int i=0;i<N;i++) {
arr[i] = new ArrayList<Integer>();
}
for(int i=0;i<M;i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken()) - 1;
int b = Integer.parseInt(st.nextToken()) - 1;
arr[a].add(b);
}
BFS(X-1);
Collections.sort(answer);
if(answer.size() == 0) {
System.out.println(-1);
return ;
}
for(int v : answer) {
System.out.println(v + 1);
}
}
static void BFS(int now) {
Queue<Integer> q = new LinkedList<>();
boolean[] visited = new boolean[N];
visited[now] = true;
q.offer(now);
int qSize = q.size();
int depth = 0;
while(qSize-- > 0) {
int temp = q.poll();
for(int next = 0; next < arr[temp].size(); next++) {
int nextNode = arr[temp].get(next);
if(visited[nextNode] == true) continue;
visited[nextNode] = true;
q.offer(nextNode);
}
if(qSize == 0) {
depth += 1;
qSize = q.size();
if(depth == K) {
while(!q.isEmpty()) {
answer.add(q.poll());
}
return ;
}
}
}
}
}
다익스트라 시간초과 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
public static int N, M, K, X;
public static int[] arr;
public static int answer = 0;
public static ArrayList<ArrayList<Node>> graph = new ArrayList<ArrayList<Node>>();
public static int[] d = new int[300001];
public static StringBuilder sb = new StringBuilder();
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
X = Integer.parseInt(st.nextToken());
Arrays.fill(d, Integer.MAX_VALUE);
for(int i=0;i<=N;i++) {
graph.add(new ArrayList<Node>());
}
for(int i=0;i<M;i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
//a번 노드에서 b노드로 가는 비용이 1 입니다.
graph.get(a).add(new Node(b, 1));
}
dijkstra(X);
boolean flag = false;
for(int i=1; i<=N;i++) {
if(d[i] == K) {
sb.append(i).append("\n");
flag = true;
}else {
}
}
if(flag == false) {
System.out.println("-1");
}else {
System.out.println(sb.toString());
}
}
public static void dijkstra(int start) {
PriorityQueue<Node> pq = new PriorityQueue<>();
pq.offer(new Node(start, 0));
d[start] = 0;
while(!pq.isEmpty()) {
Node temp = pq.poll();
int dist = temp.weight;
int now = temp.nodeB;
//현재 노드가 이미 처리된적이 있는 노드라면 무시
if(d[now] < dist) continue;
for(int i=0;i<graph.get(now).size();i++) {
int cost = d[now] + graph.get(now).get(i).weight;
if(cost < d[graph.get(now).get(i).nodeB]) {
d[graph.get(now).get(i).nodeB] = cost;
pq.offer(new Node(graph.get(now).get(i).nodeB, cost));
}
}
}
}
}
class Node implements Comparable<Node>{
int nodeB;
int weight;
@Override
public int compareTo(Node other) {
if(this.weight < other.weight) {
return 1;
}else if(this.weight == other.weight) {
return 0;
}else {
return -1;
}
}
public Node(int nodeB, int weight) {
this.nodeB = nodeB;
this.weight = weight;
}
}
DFS를 활용하여 틀린 코드입니다. 최단거리일경우에만 작동해야하지만 그렇지 않습니다.
즉, 만약 3번 위치의 최단거리로 갔을때 1->3번이 1번이라고 가정합니다.
그런데 1->2->3 번으로도 갈 수 있다고 3번의 최단거리가 2가 아닙니다. 그렇기에 BFS를 활용합니다.
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;
public class Main {
static int N, M, S, P, K, A, B, X;
// static int answer = 0;
static int[][] matrix;
static ArrayList<Integer> answer = new ArrayList<Integer>();
static ArrayList<Integer>[] arr;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
X = Integer.parseInt(st.nextToken());
arr = new ArrayList[N];
for(int i=0;i<N;i++) {
arr[i] = new ArrayList<Integer>();
}
for(int i=0;i<M;i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken()) - 1;
int b = Integer.parseInt(st.nextToken()) - 1;
arr[a].add(b);
}
boolean[] visited = new boolean[N];
visited[X-1] = true;
dfs(0, X - 1, visited);
Collections.sort(answer);
if(answer.size() == 0) {
System.out.println(-1);
return ;
}
for(int v : answer) {
System.out.println(v);
}
}
static void dfs(int depth, int now, boolean[] visited) {
if(depth == K) {
answer.add(now + 1);
return ;
}
for(int connected = 0; connected < arr[now].size(); connected++) {
int nextNode = arr[now].get(connected);
if(visited[nextNode] == false) {
visited[nextNode] = true;
dfs(depth + 1, nextNode, visited);
visited[nextNode] = false;
}
}
}
}
'알고리즘 > Shortest Path' 카테고리의 다른 글
[백준] 1254 팰린드롬 만들기 - 문자열(String) + 브루트포스(BruteForce) JAVA (0) | 2024.10.11 |
---|---|
[백준] 14938 서강그라운드 - 다익스트라(Dijkstra) JAVA (0) | 2023.08.31 |
[백준] 1753 최단경로 - 다익스트라(Dijkstra) JAVA (0) | 2023.08.28 |
[백준] 1504 특정한 최단 경로 - 다익스트라(Dijkstra) JAVA (0) | 2023.08.27 |
[백준] 1238 파티 - 다익스트라(Dijkstra) JAVA (0) | 2023.08.12 |