Study/Problem Solving
[BOJ_1647] 도시 분할 계획
monitor
2024. 1. 8. 22:08
설명
문제 조건을 요약하면 최소가 되는 두 동내의 연결 길의 합을 구하는 것인데 우선 처음 시작이 한 동내에서 두 동내로 끊는것이다. 그렇기 때문에, MST로 모두 연결하고 이때 최대의 값을 가지는 간선을 제외 시켜 버리면 최소합으로 갈 수 있는 두 동내의 연결 길을 만들 수 있다.
코드
package MST;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
/**
* MST 활용 문제
* 도시 분할 계획
*
* 두 동내의 간선중 제일 큰 간선 하나를 자른다. 이때의 MST 구조를 보면
*
* 다 연결된 거에서 (한 동내) 에서 가장 큰 간선 하나를 제거하는 구조로 두동내가 생기므로 이때가 최소의 합이 될 수 있다.
*
*/
public class BOJ_1647 {
static class Data implements Comparable<Data>{
int end;
int weight;
public Data(int end, int weight) {
this.end = end;
this.weight = weight;
}
@Override
public int compareTo(Data o) {
return this.weight - o.weight;
}
}
static boolean visited[];
static int max = 0;
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer tk = new StringTokenizer(in.readLine()," ");
int V = Integer.parseInt(tk.nextToken()); //정점의 갯수
int E = Integer.parseInt(tk.nextToken()); //간선의 갯수
ArrayList<Data>[] list = new ArrayList[V+1];
visited = new boolean[V+1];
for(int i = 0;i<V+1;i++) {
list[i] = new ArrayList();
}
for(int i = 0;i<E;i++) {
tk = new StringTokenizer(in.readLine()," ");
int from = Integer.parseInt(tk.nextToken());
int to = Integer.parseInt(tk.nextToken());
int weight = Integer.parseInt(tk.nextToken());
list[from].add(new Data(to,weight));
list[to].add(new Data(from,weight));
}
PriorityQueue<Data> q = new PriorityQueue<Data>();
q.offer(new Data(1,0)); //자기 자신은 0
int cnt = 0;
int res = 0;
while(!q.isEmpty()) {
//1.MST에 포함 되지 않은 정점 중 최소 간선 비용의 무조건 정점 찾기
// Priority Q이니깐 비용이 싼 거 부터 나오기 때문에 정리할 필요가 없구나..
Data cur = q.poll(); // logN이 되어져버림 왜냐? PriorityQueue가 바로 정렬해 버린 것을 바로 poll로 뽑아내니
if(visited[cur.end]) {//한번 등록된 곳은 다시 나오면 안됨 PriorityQueue를 쓰지 않게 되는 것과 같은 효과가 됨 -> 가지치기
continue;
}
visited[cur.end] = true;//이제 이 정점은 신장트리에 포함시키니깐 true
res+=cur.weight;//이때의 비용을 결과에 누적한다.
max = Math.max(cur.weight,max);
cnt++;
if(cnt == V) { //모든 정점이 선택됨 -> 가지치기 (N-1)번 돌았으므로 MST를 위한 모든 간선이 선택되었다.
break;
}
//2. 선택된 정점 기준으로 신장 트리에 연결 되지 않은 타 정점과의 간선 비용 최소로 업데이트
for (int j = 0; j < list[cur.end].size(); j++) {
if(!visited[list[cur.end].get(j).end]) {
q.offer(new Data(list[cur.end].get(j).end,list[cur.end].get(j).weight));//값을 업데이트함 내가 다시 가지는 곳으로 기준으로 minEdge 배열을 업데이트함
//그러면 minEdge가 가장 최소의 간선 들로만 초기화 되면서 업데이트가 될 것임 -> 그럼 다시 그 minEdge 배열 기준으로 또 찾음
}
}
}
System.out.println(res - max);
}
}
1647번: 도시 분할 계획
첫째 줄에 집의 개수 N, 길의 개수 M이 주어진다. N은 2이상 100,000이하인 정수이고, M은 1이상 1,000,000이하인 정수이다. 그 다음 줄부터 M줄에 걸쳐 길의 정보가 A B C 세 개의 정수로 주어지는데 A번
www.acmicpc.net