문제가 꽤나 길다.
간단하게 말하자면 해당 건물을 올리기 위해 먼저 다른 건물을 올려야 한다는 것이다.
하지만 여기서 특기할 점이 있다면 1번 건물을 짓고 동시에 2번과 3번 건물을 짓기 시작할 수 있다는 것이다.
따라서 4번 건물을 짓기 위해 필요한 시간은 1번 건물 10초 + 2번 건물 1초 + 3번 건물 100초 + 4번 건물 10초로 121초
가 아니라
1번 건물 10초 + (동시에 짓는 건물 중 오래걸리는 시간(2번, 3번))100초 + 4번 건물 10초로 120초이다.
이런 개념을 가지고 가면 간단하게 위상 정렬로 풀린다.
다른 건 다 위상정렬과 비슷하나 추가적으로 필요한 것은
최소의 시간을 기록할 DP 배열과 건물짓는데 걸리는 시간을 비교할 방법이다.
DP[1] (1번째 값) 은 건물1의 건축 시간으로 초기화하고,
Queue를 뽑으면서 dp[i]를 갱신한다.
while(!q.isEmpty()){
int tmp = q.poll();
order[tmp]--;
for(Node n: list[tmp]){
order[n.v]--;
if(dp[n.v]<dp[tmp]+arr[n.v])
dp[n.v]=dp[tmp]+arr[n.v];
if(order[n.v]==0)
q.add(n.v);
}
}
여기서는 다음 건물과 해당 건물을 짓기 위한 시간을 저장할 수 있는 Node 클래스를 만들었다
class Node{
int v;
int w;
Node(int v,int w){
this.v=v;
this.w=w;
}
}
또 진입 차수를 저장하는 order 배열을 만들어 진입차수를 관리했다.
그 후 진입 차수가 0인 노드를 큐에 넣고
큐가 공백상태가 될 때까지 해당 구문을 반복했다.
이때 dp 배열에 입력할 때는 진입 정점에서 진출 정점까지 걸리는 시간,
즉 해당 건물을 준공하고 다음 건물을 지을 때 걸리는 시간이 최대인 것을 넣는다.
이는 2번과 3번 건물에서 4번 건물로 넘어갈 때와 같은 상황에서
동시에 짓는다는 것을 가정할 때 가장 오래걸리는 시간을 입력하는 것과 같다.
2번이 아무리 빨리 끝나도 결국 4번 건물을 짓기 위해서는
3번 건물을 다 지어야 하기 때문이다.
해당 건물 빌드로 진입하기 위해 그 전 빌드에서 건축시간이 가장 오래걸리는 것을 입력하는 것이다.
이렇게 작성하면 문제가 풀린다.
다음은 문제풀이 코드 전체이다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
static int n, k;
static int []arr;
static int []order;
static int [] dp;
static LinkedList<Node>[] list;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T=Integer.parseInt(br.readLine());
for(int t=0;t<T;t++) {
StringTokenizer st = new StringTokenizer(br.readLine());
n=Integer.parseInt(st.nextToken());
k=Integer.parseInt(st.nextToken());
arr=new int [n+1];
order=new int [n+1];
list=new LinkedList[n+1];
dp=new int [n+1];
for(int i=0;i<n+1;i++) {
list[i]=new LinkedList<>();
}
st=new StringTokenizer(br.readLine());
for(int i=1;i<=n;i++) {
arr[i]=Integer.parseInt(st.nextToken());
}
for(int i=0;i<k;i++) {
st=new StringTokenizer(br.readLine());
int a= Integer.parseInt(st.nextToken());
int b=Integer.parseInt(st.nextToken());
list[a].add(new Node(b,arr[b]));
order[b]++;
}
int w=Integer.parseInt(br.readLine());
Queue<Integer> q = new LinkedList<>();
for(int i=1;i<=n;i++) {
if(order[i]==0) {
q.add(i);
dp[i]=arr[i];
}
}
while(!q.isEmpty()) {
int tmp=q.poll();
order[tmp]--;
for(Node n:list[tmp]) {
order[n.v]--;
if(dp[n.v]<dp[tmp]+arr[n.v])
dp[n.v]=dp[tmp]+arr[n.v];
if(order[n.v]==0) {
q.add(n.v);
}
}
}
bw.write(String.valueOf(dp[w]));
bw.newLine();
}
bw.close();
br.close();
}
}
class Node{
int v;
int w;
Node(int v,int w){
this.v=v;
this.w=w;
}
}
'알고리즘 > 백준' 카테고리의 다른 글
1504번 특정한 최단 경로 G4 (0) | 2023.04.03 |
---|---|
2252번 줄 세우기 G3 (0) | 2023.04.03 |
백준 1922번 네트워크 연결 G4 (0) | 2023.03.29 |
백준 1197번 최소 스패닝 트리 G4 (0) | 2023.03.29 |