본문 바로가기
백준/그래프

백준 2056. 작업

by 29살아저씨 2021. 9. 29.
반응형

🅰 백준 2056. 작업

 

2056번: 작업

수행해야 할 작업 N개 (3 ≤ N ≤ 10000)가 있다. 각각의 작업마다 걸리는 시간(1 ≤ 시간 ≤ 100)이 정수로 주어진다. 몇몇 작업들 사이에는 선행 관계라는 게 있어서, 어떤 작업을 수행하기 위해

www.acmicpc.net

✏️ 문제 풀이

  • 순서가 주어지므로 위상정렬의 개념을 이용하여서 풀었다.
  • 일단 위상정렬이랑 비슷하지만 선행관계가 없는 작업들은 동시에 수행되기 때문에 이 부분을 생각해내는데 시간이 조금 걸렸다.
  • pq에 저장되는 정점들은 comparable을 이용하여 수행시간이 작은 순으로 정렬을 시켜서 하나씩 뽑아낸다.
  • pq에는 들어오는 간선이 없는 정점부터 저장을 해서 탐색을 시작한다.
  • cur = pq.poll() 한 정점이 걸리는 시간을 ans에 반복해서 저장시켜준다.
  • 1. 만약 pq에 정점이 2개이상 있다면 (동시에 수행가능한 작업들이 있다면) cur의 시간만큼을 빼준 뒤 큐에 다시 넣어줘야 한다. (그래야 시간 중복이 안일어난다)
    • 큐에서 빼서 다시 큐에 넣어줘야 하기때문에 임시리스트 temp에 동시수행 가능한 정점만큼 cur의 시간을 빼준 뒤 저장해두고 나중에 큐에 다시 넣어주었다.
  • 2. 이제 cur과 연결된 정점들 중 들어오는 간선이 1인(cur 하나뿐인) 노드들을 탐색하여 pq에 넣어준다
    • cur이 가리키는 정점들은 cur과의 간선이 끊어지기 때문에 connect[node.vertex]--; 를 해서 연결된 간선 수를 최신화 시켜준다.
  • 3. 임시리스트 temp에 저장해 둔 정점들을 다시 pq에 넣어주고 임시리스트는 temp.clear()를 통해 초기화 시켜준다.
  • 큐가 빌때까지 반복해서 수행하다 보면 ans에 최소 시간이 저장된다.

✏️ 소스코드

package graph;

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

class Node implements Comparable<Node> { // 시간 순으로 정렬되도록 comparable 해줌
	int vertex;
	int time;

	Node(int v, int t) {
		vertex = v;
		time = t;
	}

	@Override
	public int compareTo(Node e) {
		return this.time <= e.time ? -1 : 1;
	}

}

public class Main_골드4_2056_작업 {
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		PriorityQueue<Node> pq = new PriorityQueue<>(); // 우선 순위 큐에 저장하여 시간이 적은 순으로 정점 탐색
		ArrayList<Node> list[]; // 인접 리스트 구현
		LinkedList<Node> temp = new LinkedList<>(); // 선행관계가 없는 작업들 동시 수행시 시간 차감을 위한 temp리스트
		int N = Integer.parseInt(br.readLine());
		int connect[] = new int[N + 1]; // 위상정렬을 하기위한 정점으로 들어오는 간선 수 체크
		int time[] = new int[N + 1]; // 작업마다 걸리는 시간 저장
		list = new ArrayList[N + 1];
		for (int i = 0; i <= N; i++) { // 인접리스트 초기화
			list[i] = new ArrayList<>();
		}

		for (int i = 1; i <= N; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int T = Integer.parseInt(st.nextToken());
			int relation = Integer.parseInt(st.nextToken());
			time[i] = T; // i번 작업에서 걸리는 시간 저장
			for (int j = 0; j < relation; j++) { // 선행관계에 있는 작업들의 수만 큼 
				int next = Integer.parseInt(st.nextToken());
				list[next].add(new Node(i, T)); // list에 저장
				connect[i]++; // i로 들어오는 간선 수 ++
			}
		}
		for (int i = 1; i <= N; i++) { // 들어오는 간선이 없는 정점먼저 탐색
			if (connect[i] == 0) {
				pq.add(new Node(i, time[i]));
			}
		}
		int ans = 0;
		while (!pq.isEmpty()) {
			Node cur = pq.poll();
			ans += cur.time;
			while (!pq.isEmpty()) { // 동시 작업이 가능한 정점이 있을 경우
				Node next = pq.poll();
				temp.add(new Node(next.vertex, next.time - cur.time)); // 임시 리스트에 적게 걸리는 시간만큼 빼준 정점 저장
			}
			for (Node node : list[cur.vertex]) { // cur과 연결된 노드 중 
				if(connect[node.vertex] == 1) pq.add(node); // 들어오는 정점이 1개인 노드 pq에 저장
				connect[node.vertex]--;	// node.vertex에 cur.vertex 끊어지므로 간선 수--; 
			}
			for (Node node : temp) { // 시간 최신화 한 노드 큐에 다시 저장
				pq.add(node);
			}
			temp.clear(); // 임시 리스트 초기화
		}
		System.out.println(ans);
	}
}

 

✅ 후기

  • 위상정렬을 이용한 문제집, 줄세우기보다 생각할게 많은 문제였는데 골드 4라니, 살짝 놀랬다.
  • 하지만 하나하나 풀어서 쓴 후 생각한대로 코딩을 하니 정답을 맞출 수 있었다. 
반응형

'백준 > 그래프' 카테고리의 다른 글

백준 1766. 문제집  (0) 2021.09.28
백준 2252. 줄 세우기  (0) 2021.09.28

댓글