문제 링크 : https://www.acmicpc.net/problem/16562
이 문제는 유니온 파인드를 이용하여 풀 수 있습니다.
친구의 친구는 친구다 라는 명제를 이용하여 친구 관계를 하나의 그룹으로 유니온 파인드를 이용하여 묶어줍니다. 이 때 친구 비용이 더 적은 인덱스를 부모 인덱스로 하여 부모 배열을 채워줍니다.
이후 각 친구 별 루트 인덱스를 확인하여 체크되어있지 않았다면 체크 후 그 값을 결과에 더하고 현재 친구 인덱스 역시 체크를 진행해줍니다. 이 때 루트 인덱스 대신 부모 인덱스를 탐색한다면 1단계의 부모만 탐색 가능하고 그 이후 단계를 탐색할 수 없기 때문에 find를 이용한 루트 인덱스를 탐색해야 하며, 루트 인덱스와 현재 인덱스 모두 체크를 해주어야 중복되어 더해지지 않습니다.
다음은 코드입니다.
import java.util.*;
import java.io.*;
class Main{
static int[] cost;
static int[] parent;
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
cost = new int[N+1];
parent = new int[N+1];
st = new StringTokenizer(br.readLine());
for(int i=1;i<=N;i++) cost[i] = Integer.parseInt(st.nextToken());
for(int i=0;i<=N;i++) parent[i] = i;
for(int i=0;i<M;i++){
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
if(a > b) union(b,a);
else union(a,b);
}
long cnt = 0;
boolean[] check = new boolean[N+1];
for(int i=1;i<=N;i++){
int idx = find(i);
if(!check[idx]){
cnt += cost[idx];
check[idx] = true;
}
check[i] = true;
}
if(cnt > k) System.out.println("Oh no");
else System.out.println(cnt);
}
static void union(int a, int b){
a = find(a);
b = find(b);
if(cost[a] > cost[b]) parent[a] = b;
else parent[b] = a;
}
static int find(int a){
if(a == parent[a]) return a;
else return parent[a] = find(parent[a]);
}
}