https://www.acmicpc.net/problem/18352

 

18352번: 특정 거리의 도시 찾기

첫째 줄에 도시의 개수 N, 도로의 개수 M, 거리 정보 K, 출발 도시의 번호 X가 주어진다. (2 ≤ N ≤ 300,000, 1 ≤ M ≤ 1,000,000, 1 ≤ K ≤ 300,000, 1 ≤ X ≤ N) 둘째 줄부터 M개의 줄에 걸쳐서 두 개

www.acmicpc.net

코드설명

다익스트라(Dijkstra) 혹은 BFS(너비우선탐색) 를 통해 해결할 수 있는 문제입니다.

 

다익스트라(Dijkstra)를 활용하여 풀경우에는 시간초과가 납니다.

 

시간복잡도를 비교해보겠습니다.

다익스트라의 시간복잡도는 O(ELogV) 입니다.

E는 간선의 개수, V는 노드의 개수입니다. 

문제에 주어진 조건은

- 노드의 개수는, 2 ≤ ≤ 300,000개입니다.

- 간선의 개수는 1 ≤ ≤ 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;
			}
		}
		
	}
	
}

+ Recent posts