1. 개념
두 노드를 연결할 때, 가중치가 최소인 것을 구하는 알고리즘
2. 설명
1부터 시작할 때, minEdge[] 배열을 나타냈다.
각 노드를 탐색하면서 minEdge에 가중치를 누적 시킨다.
3. 문제
1753번: 최단경로
첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1≤V≤20,000, 1≤E≤300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1≤K≤V)가 주어진다.
www.acmicpc.net
for문을 전부 탐색해서 최소 누적치를 찾는 풀이 -> 시간초과 때문에, 노드 수가 많으면 못 푼다.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static class Edge{
int v, w;
public Edge(int v, int w) {
this.v = v;
this.w = w;
}
}
public static void main(String[] args) {
//입력
Scanner sc = new Scanner(System.in);
int V = sc.nextInt();
int E = sc.nextInt();
int K = sc.nextInt();
int dist[] = new int[V];//노드까지의 최소 거리 저장
Arrays.fill(dist, Integer.MAX_VALUE);
ArrayList<Edge> list[] = new ArrayList[V];
for (int i = 0; i < V; i++) {
list[i]=new ArrayList<>();
}
for (int i = 0; i < E; i++) {
int u = sc.nextInt()-1;
int v = sc.nextInt()-1;
int w = sc.nextInt();
list[u].add(new Edge(v, w));
}
boolean visit[] = new boolean[V];
dist[K-1] = 0;
for (int i = 0; i < V; i++) {
//dist값이 젤 작은 정점의 번호를 찾으시오
int min=Integer.MAX_VALUE;
int index = -1;
//가장 짧은 시작점을 찾고
for (int j = 0; j < V; j++) {
if(!visit[j] && min > dist[j]) {
min = dist[j];
index = j;
}
}
if(index == -1) break;
//시작 정점에 연결된 간선하고 지금까지 최소거리 하고 더했을때 더 값이 작다면 갱신한다
for (Edge next : list[index]) {
if(!visit[next.v] && dist[next.v] > dist[index] + next.w) {
dist[next.v] = dist[index] + next.w;
}
}
visit[index] = true;
}
for (int k : dist) {
if(k==Integer.MAX_VALUE) {
System.out.println("INF");
}else {
System.out.println(k);
}
}
}
}
이 부분을 우선순위 큐로 바꿀 필요가 있다.
for (int j = 0; j < V; j++) {
if(!visit[j] && min > dist[j]) {
min = dist[j];
index = j;
}
}
우선순위 큐를 사용 풀이
import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Main {
static class Edge implements Comparable<Edge> {
int no;
int w;// total weight
public Edge(int to, int w) {
this.no = to;
this.w = w;
}
@Override
public int compareTo(Edge o) {
return this.w - o.w;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int V = sc.nextInt();
int E = sc.nextInt();
int startidx = sc.nextInt();
ArrayList<Edge> map[] = new ArrayList[V + 1];
for (int i = 1; i <= V; i++) {
map[i] = new ArrayList<>();
}
int minEdges[] = new int[V + 1];
boolean visit[] = new boolean[V + 1];
Arrays.fill(minEdges, Integer.MAX_VALUE);
minEdges[startidx] = 0;
for (int i = 0; i < E; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
int w = sc.nextInt();
map[u].add(new Edge(v, w));
}
PriorityQueue<Edge> pq = new PriorityQueue<>();
pq.add(new Edge(startidx, 0));
while (!pq.isEmpty()) {
Edge cur = pq.poll();
if (visit[cur.no])
continue;
visit[cur.no] = true;
for (Edge next : map[cur.no]) {
if (!visit[next.no] && minEdges[next.no] > next.w + minEdges[cur.no]) {
minEdges[next.no] = next.w + minEdges[cur.no];
pq.add(new Edge(next.no, minEdges[next.no]));
}
}
}
for (int i = 1; i <= V; i++) {
if (minEdges[i] == Integer.MAX_VALUE)
System.out.println("INF");
else
System.out.println(minEdges[i]);
}
}
}
//priorityqueue<Edge>
//q.add(add(index, weight))
//while !q.isempty
//Edge cur = q.poll
//for Edge next : map[cur.no]
//if !visit and minEdge[next.no] > cur.w + minEdge[cur.no]
//minEdge[next.no] = cur.w + minEdge[cur.no]
//pq.add next.no, minEdge[next.no]
우선순위큐를 위해 Comparable구현
static class Edge implements Comparable<Edge> {
int no;
int w;// total weight
public Edge(int to, int w) {
this.no = to;
this.w = w;
}
@Override
public int compareTo(Edge o) {
return this.w - o.w;
}
}
시작값 설정
PriorityQueue<Edge> pq = new PriorityQueue<>();
pq.add(new Edge(startidx, 0));
방문을 하지 않고, 다음 노드까지의 누적치 > 현재노드 가중치 + 현재노드 누적치 조건이 성립하면 변수 갱신
if (!visit[next.no] && minEdges[next.no] > next.w + minEdges[cur.no]) {
minEdges[next.no] = next.w + minEdges[cur.no];
pq.add(new Edge(next.no, minEdges[next.no]));
}
'알고리즘 > 코테에 필요한 지식만' 카테고리의 다른 글
투 포인터 (0) | 2020.09.25 |
---|---|
LIS 최장 증가 부분수열 (0) | 2020.09.24 |
순열과 조합 뿌시기 (0) | 2020.08.28 |
우선순위 큐 (0) | 2020.08.28 |
비트연산자 (0) | 2020.08.27 |