728x90

숨바꼭질 1679번


내가 떠올린 풀이 해설

BFS를 응용해서 푸는 문제였다. BFS()를 호출한 후 BFS에서 arr 배열을 최대 크기 배열로 생성한 후 Queue에 n을 add한다. Queue가 비어있을 때까지 반복한다. now 값에 Queue에서 poll 한 값을 대입하고 for문을 i가 3보다 작을 때까지 반복한다. 1초 후에 now - 1, now + 1, now * 2로 움직여야한다. 만약 next가 k와 같다면 arr[now]를 리턴해준다. 또한 만약 next가 0보다 크거나 같고 next가 100001보다 작아야하고 arr[next]가 0일 때 arr[next]에 arr[now] + 1을 대입한다. 그리고 Queue에 next를 add한다.


정확한 풀이

import java.util.*;
public class Baek1697 {
	static int n;
	static int k;
	static int[] arr;
	static Queue<Integer> que = new LinkedList<>();
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		k = sc.nextInt();
		
		if (n >= k) {
            System.out.println(n - k);
        } else {
            System.out.println(BFS());
        }
	}
	private static int BFS() {
		arr = new int[100001];
		que.add(n);
		arr[n] = 1;
		while(!que.isEmpty()) {
			int now = que.poll();
			for(int i = 0; i < 3; i++) {
				int next;
				if (i == 0) {
                    next = now - 1;
                } 
				else if (i == 1) {
                    next = now + 1;
                } 
                else {
                    next = now * 2;
                }
                if (next == k) {
                    return arr[now];
                }
                if (next >= 0 && next < 100001 && arr[next] == 0) {
                    arr[next] = arr[now] + 1;
                    que.add(next);
                }
			}
		}
		return 0;
	}
}

파티 1238번


내가 떠올린 풀이 해설

이 문제를 푸는데 시간이 오래 걸렸다. 다익스트라에서 조금만 응용하면 되는 문제였다. 1~N을 출발점으로 파티 마을 X까지의 거리를 다익스트라로 구한다. 그리고 반대로 파티 마을 X를 출발점으로 다익스트라를 돌려서 각 마을까지의 거리를 구했다. 그리고 이 두 값을 마을마다 더해주면 오고 가는 거리가 나오는데 이 값들 중 최댓값을 구하면 된다. time 배열은 파티 마을까지 오고 가는 거리의 값이다. 1~N 마을을 출발지로 다익스트라를 돌린 후 X까지의 거리를 time에 더해준다. 그 후 X를 출발지로 각 마을까지 거리를 구하여 time에 더해준다. 그 이후 time의 값들 중 최대값을 출력한다. 그 다음 dijkstra를 호출하고 다익스트라 메서드에서 우선순위 큐에 시작 정점을 넣어준다. 시작 지점의 가중치는 0이다. visit, distance를 초기화하고 distance에는 -1을 넣어준다. 우선순위 큐가 빌 때까지 while문을 반복한다. 현재 정점에 방문하지 않았을 때 연결된 정점들에 대해 검사를 시작한다. 연결된 정점의 가중치가 -1이거나 연결된 정점의 가중치가 현재 정점의 가중치와 현재 간선의 가중치의 합보다 클 때 값을 업데이트한다. 업데이트 후 다음 정점을 우선순위 큐에 넣어준다. Circle 클래스는 정점의 번호와 가중치를 가진다. 우선순위 큐의 타입으로 이용하기 위해 Comparable을 implements 해준다. 정렬 기준은 가중치의 오름차순이다.


 

참고 블로그

https://jellyinghead.tistory.com/79

 

[백준 1238] 파티 (자바)

난이도 : 골드 3 다익스트라 알고리즘을 이용해 풀었습니다. 2020/11/02 - [문제풀이/자바] - [백준 1753] 최단경로 (자바) [백준 1753] 최단경로 (자바) https://www.acmicpc.net/problem/1753 1753번: 최단경로..

jellyinghead.tistory.com


정확한 풀이

import java.util.*;
import java.io.*;

public class Baek1238 {
	static int[] distance;
	static boolean[] visit;
	static ArrayList<Circle>[] list;
	static PriorityQueue<Circle> que = new PriorityQueue<>();
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		int n = Integer.parseInt(st.nextToken());
		int m = Integer.parseInt(st.nextToken());
		int x = Integer.parseInt(st.nextToken());
		visit = new boolean[n + 1];
		list = new ArrayList[n + 1];
		distance = new int[n + 1];
		
		for(int i = 1; i <= n; i++) {
			list[i] = new ArrayList<Circle>();
		}
		
		for(int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int u = Integer.parseInt(st.nextToken());
			int v = Integer.parseInt(st.nextToken());
			int w = Integer.parseInt(st.nextToken());
			list[u].add(new Circle(v, w));
		}
		int time[] = new int[n+1];
        for(int i = 1; i <= n; i++) {
            dijkstra(i);
            time[i] += distance[x];
        }
        
        dijkstra(x);
        for(int i = 1; i <= n; i++)
            time[i] += distance[i];
        
        int max = 0;
        for(int i = 1; i <= n; i++) 
            max = Math.max(max, time[i]);
    
        System.out.println(max);
	}

	private static void dijkstra(int x) {
		que.offer(new Circle(x, 0));
		visit = new boolean[visit.length];
		distance = new int[distance.length];
        Arrays.fill(distance, -1);
		distance[x] = 0;
		while(!que.isEmpty()) {
			Circle current = que.poll();
			int c_v = current.vertex;
			if(visit[c_v]) {
				continue;
			}
			visit[c_v] = true;
			for(int i = 0; i < list[c_v].size(); i++) {
				Circle tmp = list[c_v].get(i);
				int next = tmp.vertex;
				int value = tmp.value;
				if(distance[next] == -1 || distance[next] > distance[c_v] + value) {
					distance[next] = distance[c_v] + value;
					que.add(new Circle(next, distance[next]));
				}
			}
		}	
	}
}	
class Circle implements Comparable<Circle> {
	int vertex, value;
	Circle(int vertex, int value) {
		this.vertex = vertex;
		this.value = value;
	}
	@Override
	public int compareTo(Circle o) {
		return value - o.value;
	}
}

오늘의 회고

오늘은 BFS와 다익스트라 문제를 풀었습니다. 두 문제 모두 조금만 응용해서 푸는 문제였고, 너무 오랫만에 BFS와 다익스트라 문제를 풀어서 시간이 오래걸렸습니다. 다른 개념들도 까먹지않게 여러 개념의 문제들을 풀어야할 것 같습니다. 조금만 화이팅하자

728x90

'알고리즘 > 알고리즘 문제풀이' 카테고리의 다른 글

백준) DP, DFS  (0) 2022.08.27
백준) HashMap  (0) 2022.07.23
백준) 우선순위 큐, DP  (0) 2022.07.18
백준) 수학(피타고라스), 이분 탐색  (0) 2022.07.16
백준) 수학, 이분 탐색  (0) 2022.07.13
728x90

다익스트라

다익스트라 알고리즘은 그래프에서 최단 거리를 구하는 알고리즘으로, 에지는 모두 양수 이어야 한다. 특정 노드에서 다른 노드들의 최단 거리를 구하는 문제가 주어졌을 때 다익스트라 알고리즘을 사용한다. 

 

시간 복잡도(노드 수 : V, 에지 수 : E)

O(ElogV)

 

다익스트라 알고리즘 핵심 이론

1. 인접 리스트로 그래프 구현하기

   다익스트라 알고리즘은 인접 행렬로 구현해도 좋지만 시간 복잡도 측면, N의 크기가 클 것을 대비해 인접 리스트를 선택하여 구현하는 것 이 좋다. 

2. 최단 거리 배열 초기화하기

   최단 거리 배열을 만들고, 출발 노드는 0, 이외의 노드는 무한으로 초기화한다. 이때 무한은 적당히 큰 값을 사용하면 된다.

3. 값이 가장 작은 노드 고르기

   최단 거리 배열에서 현재 값이 가장 작은 노드를 고른다. 여기서는 값이 0인 출발 노드에서 시작하면 된다.

4. 최단 거리 배열 업데이트하기

   선택된 노드에 연결된 에지의 값을 바탕으로 다른 노드의 값을 업데이트합니다. 1단계에서 저장해 놓은 연결 리스트를 이용해 현재 선택된 노드의 에지들을 탐색하고 업데이트하면 된다. 연결 노드 간 최단 거리는 두 값 중 더 작은 값으로 업데이트한다.

5. 과정 3 ~ 4를 반복해 최단 거리 배열 완성하기

   모든 노드가 처리될 때까지 3 ~ 4를 반복한다. 과정 4에서 선택 노드가 될 때마다 다시 선택되지 않도록 방문 배열을 만들어 처리하고, 모든 노드가 선택될 때까지 반복하면 최단 거리 배열이 완성된다.

 

최단 거리 업데이트 방법

Min(선택 노드의 최단 거리 배열의 값 + 에지 가중치, 연결 노드의 최단 거리 배열의 값)

 

다익스트라 알고리즘은 출발 노드와 그외 노드 간의 최단 거리를 구하는 알고리즘이고, 에지는 항상 양수여야 한다는 제약 조건이 있다.

많은 사람들이 다익스트라 알고리즘이 출발 노드와 도착 노드 간의 최단 거리를 구하는 알고리즘이라고 생각하는 경향이 있는데, 실제로 완성된 배열은 출발 노드와 이외의 모든 노드 간의 최단 거리를 표현한다.

 

코드로 표현

static int[] distance;
static boolean[] visit;
static ArrayList<Edge>[] list;
static PriorityQueue<Edge> q = new PriorityQueue<Edge>();

for(int i = 1; i <= S; i++) {
	list[i] = new ArrayList<Edge>();
}
for(int i = 0; i <= S; i++) {
	distance[i] = Integer.MAX_VALUE;
}
for(int i = 0; i < E; i++) {  // 가중치가 있는 인접 리스트 초기화하기
	list[u].add(new Edge(v, w));
}
q.add(new Edge(k, 0));   // k를 시작점으로 설정하기
distance[k] = 0;
while(!q.isEmpty()) {
	Edge current = q.poll();
    int c_v = current.vertex;
    if(visit[c_v]) {
    	continue;   // 이미 방문한 적이 있는 노드는 다시 큐에 넣지 않음
    }
    visit[c_v] = true;
    for(int i = 0; i < list[c_v].size(); i++) {
    	Edge tmp = list[c_v].get(i);
        int next = tmp.vertex;
        int value = tmp.value;
        if(distance[next] > distance[c_v] + value) { // 최소 거리로 업데이트하기
        	distance[next] = value + distance[c_v];
            q.add(new Edge(next, distacne[next]));
        }
    }
 }
class Edge implements Comparable<Edge> {
	int vertex, value;
    Edge(int vertex, int value) {
    	this.vertex = vertex;
        this.value = value;
    }
    public int compareTo(Edge e) {
    	if(this.value > e.value) {
        	return 1;
        }
        else {
        	return -1;
        }
  	}
}

위의 코드는 알고리즘과 관련된 코드만 표현한 코드입니다. 생략된 부분이 많으니 참고 바랍니다.

728x90

'알고리즘 > 알고리즘 이론' 카테고리의 다른 글

플로이드-위셜  (0) 2022.06.23
벨만 - 포드  (0) 2022.06.21
위상 정렬  (0) 2022.06.21
유니온 파인드  (0) 2022.06.21
그리디  (0) 2022.06.20
728x90

57번 최소비용 구하기


내가 떠올린 풀이 해설

버스의 비용의 범위가 음수가 아니기 때문에 이 문제는 다익스트라 알고리즘을 이용해 해결할 수 있다. 도시의 개수가 최대 1,000개 이므로 인접 행렬 방식으로 해결할 수 있지만 인접 리스트로 풀었다. 도시는 노드, 도시 간 버스 비용은 에지로 나타낸다.

도시 개수의 크기만큼 인접 리스트 배열의 크기를 설정한다. 이때 버스의 비용이 존재하므로 인접 리스트 배열의 자료형이 될 클래스를 선언한다. 그리고 버스 개수의 크기만큼 반복문을 돌면서 그래프를 리스트 배열에 저장한다. 다익스트라 알고리즘을 수행한다. 최단 거리를 완성되면 출력한다.


정확한 풀이

import java.io.*;
import java.util.*;

public class Baek1916 {
	static int n, m;
	static ArrayList<Node>[] list;
	static boolean[] visit;
	static int[] distance;
	
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		StringTokenizer st;
		
		n = Integer.parseInt(br.readLine());
		m = Integer.parseInt(br.readLine());
		
		list = new ArrayList[n + 1];
		visit = new boolean[n + 1];
		distance = new int[n + 1];
		
		for(int i = 0; i <= n; i++) {
			list[i] = new ArrayList<Node>();
		}
		
		for(int i = 0; i <= n; i++) {
			distance[i] = Integer.MAX_VALUE;
		}
		
		for(int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());
			int e = Integer.parseInt(st.nextToken());
			int v = Integer.parseInt(st.nextToken());
			list[s].add(new Node(e, v));
		}
		st = new StringTokenizer(br.readLine());
		int start = Integer.parseInt(st.nextToken());
		int end = Integer.parseInt(st.nextToken());
		dijkstra(start, end);
		
		System.out.println(distance[end]);
		
	}
	private static int dijkstra(int start, int end) {
		PriorityQueue<Node> que = new PriorityQueue<>();
		que.offer(new Node(start, 0));
		distance[start] = 0;
		while(!que.isEmpty()) {
			Node cur = que.poll();
			int c_v = cur.vertex;
			if(!visit[c_v]) {
				visit[c_v] = true;
				for(Node n : list[c_v]) {
					if(!visit[n.vertex] && distance[n.vertex] > distance[c_v] + n.value) {
						distance[n.vertex] = distance[c_v] + n.value;
						que.add(new Node(n.vertex, distance[n.vertex]));
					}
				}	
			}
		}
		return distance[end];
	}

}
class Node implements Comparable<Node>{
	int vertex;
	int value;
	public Node(int vertex, int value) {
		this.vertex = vertex;
		this.value = value;
	}
	@Override
	public int compareTo(Node o) {
		return value - o.value;
	}
}

59번 타임머신


내가 떠올린 풀이

에지 리스트에 에지 데이터를 저장한 후 거리 배열을 초기화한다. 최초 시작점에 해당하는 거리 배열값은 0으로 초기화한다. 벨만-포드 알고리즘을 수행한다. 음수 사이클이 존재하면 -1, 존재하지 않으면 거리 배열의 값을 출력한다. 단, 거리 배열의 값이 INF일 경우에는 -1을 출력한다.

벨만-포드 수행과정

1. 모든 에지와 관련된 정보를 가져온 후 다음 조건에 따라 거리 배열의 값을 업데이트한다.

  • 출발 노드가 방문한 적이 없는 노드(출발 노드 거리 == INF)일 때 값을 업데이트하지 않는다.
  • 출발 노드의 거리 배열값 + 에지 가중치 < 종료 노드의 거리 배열 값일 때 종료 노드의 거리 배열 값을 업데이트한다.

2. 노드 개수 -1번만큼 1번을 반복한다.

3. 음수 사이클 유무를 알기 위해 모든 에지에 관해 다시 한번 1번을 수행한다. 이때 한 번이라도 값이 업데이트되면 음수 사이클이 존재한다고 판단한다. 


정확한 풀이

import java.io.*;
import java.util.*;

public class Baek11657 {
	static int n, m;
	static long distance[];
	static Edge edges[];
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		int n = Integer.parseInt(st.nextToken());
		int m = Integer.parseInt(st.nextToken());
		
		edges = new Edge[m + 1];
		distance = new long[n + 1];
		for(int i = 0; i <= n; i++) {
			distance[i] = Integer.MAX_VALUE;
		}
		for(int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());
			int e = Integer.parseInt(st.nextToken());
			int v = Integer.parseInt(st.nextToken());
			edges[i] = new Edge(s, e, v);
		}
		distance[1] = 0;
		for(int i = 1; i < n; i++) {
			for(int j = 0; j < m; j++) {
				Edge edge = edges[j];
				if(distance[edge.s] != Integer.MAX_VALUE
						&& distance[edge.e] > distance[edge.s] + edge.v) {
					distance[edge.e] = distance[edge.s] + edge.v;
				}
			}
		}
		boolean mCycle = false;
		for(int i = 0; i < m; i++) {
			Edge edge = edges[i];
			if(distance[edge.s] != Integer.MAX_VALUE
					&& distance[edge.e] > distance[edge.s] + edge.v) {
				mCycle = true;
			}
		}
		if(!mCycle) {
			for(int i = 2; i <= n; i++) {
				if(distance[i] == Integer.MAX_VALUE) {
					System.out.println("-1");
				}
				else {
					System.out.println(distance[i]);
				}
			}
		}
		else {
			System.out.println("-1");
		}
	}
}
class Edge {
	int s;
	int e;
	int v;
	public Edge(int s, int e, int v) {
		this.s = s;
		this.e = e;
		this.v = v;
	}
}

오늘의 회고

오늘은 다익스트라 한 문제와 벨만-포드 알고리즘 개념과 관련된 문제를 풀었습니다. 아직 다익스트라와 벨만-포드 구현에 대해 많이 부족한 것 같습니다. 내일도 이와 관련된 문제들을 풀고 다시 한번 개념에 대해 공부하겠습니다. 

728x90
728x90

54번 게임 개발


내가 떠올린 풀이 해설

각 건물을 노드라고 생각하면 그래프 형태에서 노드 순서를 정렬하는 알고리즘인 위상 정렬을 사용하는 문제이다. 건물 수가 최대 500, 시간 복잡도가 2초이므로 시간제한 부담은 거의 없다. 입력을 바탕으로 자료구조를 초기화한다 인접 리스트로 그래프를 표현할 때는 인접 노드, 건물 번호를 Node로 선언하여 연결한다. 진입 차수 배열은 [0, 1, 2, 1], 정답 배열은 모두 0으로 초기화한다. 위상 정렬을 실행하면서 각 건물을 짓는데 걸리는 최대 시간을 업데이트합니다. 업데이트 방법은 Math.max(현재 건물에 저장된 최대 시간, 이전 건물에 저장된 최대 시간 + 현재 건물의 생산 시간)이다. 정답 배열에 자기 건물을 짓는 데 걸리는 시간을 더한 후 정답 배열을 차례대로 출력한다.


정확한 풀이

import java.io.*;
import java.util.*;
public class Baek1516 {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		ArrayList<ArrayList<Integer>> list = new ArrayList<>();
		int[] indegree = new int[n + 1];
		int[] selfBuild = new int[n + 1];
		for(int i = 0; i <= n; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			selfBuild[i] = Integer.parseInt(st.nextToken());
			int r = Integer.parseInt(st.nextToken());
			
			while(true) {
				if(r == -1) {
					break;
				}
				list.get(r).add(i);
				indegree[i]++;
			}
		}
		Queue<Integer> que = new LinkedList<>();
		for(int i = 1; i <= n; i++) {
			if(indegree[i] == 0) {
				que.offer(i);
			}
		}
		int[] result = new int[n + 1];
		while(!que.isEmpty()) {
			int now = que.poll();
			for(int i : list.get(now)) {
				indegree[i]--;
				result[i] = Math.max(result[now], result[now] + selfBuild[now]);
				if(indegree[i] == 0) {
					que.offer(i);
				}
			}
		}
		for(int i = 1; i <= n; i++) {
			System.out.println(result[i] + selfBuild[i]);
		}
	}
}

56번 최단경로


내가 떠올린 풀이 해설

시작점과 다른 노드와 관련된 최단 거리를 구하는 문제이다. 다익스트라 알고리즘의 가장 기본적인 형태를 구현할 수 있는지를 묻는 문제이다. 인접 리스트에 노드를 저장하고 거리 배열을 초기화한다. 거리 배열은 0으로 초기화한다. 최초 시작점을 큐에 삽입하고, 다음 과정에 따라 다익스트라 알고리즘을 수행한다. 마지막으로 완성된 거리 배열의 값을 출력한다.

다익스트라 수행 과정

1. 거리 배열에서 아직 방문하지 않은 노드 중 현재 값이 가장 작은 노드를 선택한다.

2. 해당 노드와 연결된 노드들의 최단 거릿값을 다음 공식을 이용해 업데이트한다.

  • Min(선택 노드의 거리 배열의 값 + 에지의 가중치, 연결 노드의 거리 배열의 값이 업데이트된 경우 연결 노드를 큐에 삽입)

3. 큐가 빌 때까지 반복한다.


정확한 풀이

import java.io.*;
import java.util.*;

public class Baek1753 {
	static int n,m,k;
	static boolean[] visit;
	static int[] distance;
	static ArrayList<Edge>[] list;
	static PriorityQueue<Edge> que = new PriorityQueue<>();
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		int n = Integer.parseInt(st.nextToken());
		int m = Integer.parseInt(st.nextToken());
		
		int k = Integer.parseInt(br.readLine());
		
		distance = new int[n + 1];
		list = new ArrayList[n + 1];
		visit = new boolean[n + 1];
		
		for(int i = 1; i <= n; i++) {
			list[i] = new ArrayList<Edge>();
		}
		for(int i = 1; i <= n; i++) {
			distance[i] = Integer.MAX_VALUE;
		}
		for(int i = 0; i < n; i++) {
			st = new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());
			int e = Integer.parseInt(st.nextToken());
			int v = Integer.parseInt(st.nextToken());
			list[s].add(new Edge(e, v));
		}
		que.add(new Edge(k, 0));
		distance[k] = 0;
		while(!que.isEmpty()) {
			Edge current = que.poll();
			int c_v = current.vertex;
			if(visit[c_v]) {
				continue;
			}
			visit[c_v] = true;
			for(int i = 0; i < list[c_v].size(); i++) {
				Edge tmp = list[c_v].get(i);
				int next = tmp.vertex;
				int value = tmp.value;
				if(distance[next] > distance[c_v] + value) {
					distance[next] = value + distance[c_v];
					que.add(new Edge(next, distance[next]));
				}
			}
		}
		for(int i = 1; i <= m; i++) {
			if(visit[i]) {
				System.out.println(distance[i]);
			}
			else {
				System.out.println("INF");
			}
		}
	}
}
class Edge implements Comparable<Edge>{
	int vertex, value;
	Edge(int vertex, int value) {
		this.vertex = vertex;
		this.value = value;
	}
	@Override
	public int compareTo(Edge o) {
		if(this.value > o.value) {
			return 1;
		}
        else {
			return -1;
		}
	}
}

오늘의 회고

오늘은 위상 정렬과 다익스트라 개념 공부와 다익스트라 기본 문제를 풀었습니다. 기본 문제인데 풀기 힘들었습니다. 또한 Do it! 알고리즘 코딩 테스트 (26번 ~ 28번)까지 복습을 진행하였습니다. 처음 알고리즘을 공부할 때는 재미도 없고 알고리즘이 필요가 있을까라는 생각을 했었는데 알고리즘을 공부하면서 점점 재미가 있고 모르는 문제를 고민하면서 해결 능력을 길러나가는 점에서 많은 도움이 될 것이라고 생각합니다. 매일 똑같은 말이지만 오늘보다 나은 내일을 위해 다짐을 한다고 생각해 주시면 감사하겠습니다. 성장하는 저를 위해 꾸준히 천천히 한 발 한 발 나아가겠습니다.

728x90

+ Recent posts