알고리즘

[Java] 백준 1948번 임계경로

J3SUNG 2023. 3. 12. 15:38
728x90

 

위상정렬 문제입니다.

위상정렬 알고리즘을 사용해서 가장 긴 시간을 구합니다.
구하는 과정에서 각 위치에 시간, 어떤위치에서 왔는지, 어떤 경로로 왔는지 기록합니다.
만약 그 위치를 더 높은 시간으로 간다면 위의 값들을 새롭게 갱신해줍니다.
만약 그 위치를 같은 시간으로 간다면 현재위치와 경로도 추가적으로 넣어줍니다.
만약 그 위치를 더 낮은 시간으로 간다면 해당 결과는 무시합니다.

위의 과정을 통해서 가장 긴 시간을 구하고 이전 경로와 위치를 알 수 있습니다.
이제 목적지에서부터 위의 경로와 위치를 사용해서 역추적을 합니다.
visit배열을 주어서 중복 방문하는 경우를 처리해주고 경로의 수를 출력해주었습니다.

 

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	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 = null;

		int n = Integer.parseInt(br.readLine());
		int m = Integer.parseInt(br.readLine());
		int[] size = new int[n + 1];
		int[] visit = new int[m + 1];
		Queue<Data> q = new LinkedList<>();
		Queue<Integer> bq = new LinkedList<>();
		ArrayList<ArrayList<Data>> al = new ArrayList<>();
		ArrayList<LocInfo> loc = new ArrayList<>();

		for (int i = 0; i <= n; ++i) {
			ArrayList<Data> temp1 = new ArrayList<>();
			LocInfo temp2 = new LocInfo(0);
			al.add(temp1);
			loc.add(temp2);
		}

		for (int i = 0; i < m; ++i) {
			st = new StringTokenizer(br.readLine());
			int a = Integer.parseInt(st.nextToken());
			int b = Integer.parseInt(st.nextToken());
			int c = Integer.parseInt(st.nextToken());
			al.get(a).add(new Data(a, b, c, i));
			++size[b];
		}

		st = new StringTokenizer(br.readLine());
		int s = Integer.parseInt(st.nextToken());
		int e = Integer.parseInt(st.nextToken());
		Data d;
		q.add(new Data(s, s, 0, 0));
		while (!q.isEmpty()) {
			d = q.poll();
			if (loc.get(d.cur).time < d.value + loc.get(d.prev).time) { // 현재 위치의 저장된 시간 < 비용 + 이전위치 저장된 시간
				loc.get(d.cur).time = d.value + loc.get(d.prev).time; // 시간 변경
				loc.get(d.cur).visit.index = d.prev + " ";
				loc.get(d.cur).visit.load = d.load + " ";
			} else if (loc.get(d.cur).time == d.value + loc.get(d.prev).time) { // 시간이 같을 경우
				if (d.prev != d.cur) {
					loc.get(d.cur).visit.index += d.prev + " ";
					loc.get(d.cur).visit.load += d.load + " ";
				}
			}
			if (size[d.cur] > 1) {
				--size[d.cur];
				continue;
			}

			for (int i = 0; i < al.get(d.cur).size(); ++i) {
				q.add(al.get(d.cur).get(i));
			}
		}

		int ansSize = 0;
		bq.add(e);
		while (!bq.isEmpty()) {
			int num = bq.poll();
			String[] arrIndex = loc.get(num).visit.index.split(" ");
			String[] arrLoad = loc.get(num).visit.load.split(" ");
			for (int i = 0; i < arrIndex.length; ++i) {
				if (arrLoad[i] == "" || visit[Integer.parseInt(arrLoad[i])] == 1) {
					continue;
				}
				visit[Integer.parseInt(arrLoad[i])] = 1;
				++ansSize;
				bq.add(Integer.parseInt(arrIndex[i]));
			}
		}

		bw.write(loc.get(e).time + "\n");
		bw.write(ansSize + "\n");
		bw.close();
	}

	public static class LocInfo {
		public Pair visit = new Pair();
		public int time;

		public LocInfo(int time) {
			this.time = time;
		}
	}

	public static class Data {
		public int prev;
		public int cur;
		public int value;
		public int load;

		public Data(int prev, int cur, int value, int load) {
			this.prev = prev;
			this.cur = cur;
			this.value = value;
			this.load = load;
		}
	}

	public static class Pair {
		public String index = "";
		public String load = "";
	}
}