## 과제 : 백준 문제 풀이
목표 : 백준 문제를 풀어본다.
- [상근이의 여행](https://www.acmicpc.net/problem/9372)
- [최대 유량](https://www.acmicpc.net/problem/6086)
---
## 과제 : 백준 문제 풀이 모범답안
### 상근이의 여행
```java
import java.io.*;
import java.util.*;
public class Main {
static int[] parent;
static int find(int x) {
if (parent[x] == x) return x;
return parent[x] = find(parent[x]);
}
static boolean union(int x, int y) {
x = find(x);
y = find(y);
if (x != y) {
parent[y] = x;
return true;
}
return false;
}
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
int T = scanner.nextInt();
StringBuilder sb = new StringBuilder();
for (int t = 0; t < T; t++) {
int N = scanner.nextInt();
int M = scanner.nextInt();
parent = new int[N + 1];
for (int i = 1; i <= N; i++) parent[i] = i;
int edgeCount = 0;
for (int i = 0; i < M; i++) {
int u = scanner.nextInt();
int v = scanner.nextInt();
if (union(u, v)) {
edgeCount++;
}
}
sb.append(edgeCount).append("\n");
}
System.out.print(sb.toString());
scanner.close();
}
}
```
해당 문제는 위처럼 최소 신장 트리로 해결할 수도 있지만, 더 간단한 방법으로 해결할 수 있다.
최소 신장 트리는 노드의 수 - 1개의 간선으로 구성되어 있기 때문에, 모든 국가가 연결되어 있다면 간선의 수는 N - 1이 된다.
여기서는 간선의 수를 구하는 것이 목적이므로, 간선의 수만 구하면 된다.
```java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt(); // 테스트 케이스의 수
for (int i = 0; i < T; i++) {
int N = sc.nextInt(); // 국가의 수
int M = sc.nextInt(); // 비행기의 종류
// 비행 경로 입력 받기 (실제로 경로를 저장할 필요는 없음)
for (int j = 0; j < M; j++) {
int a = sc.nextInt();
int b = sc.nextInt();
}
// 국가의 수 - 1 출력 (최소 신장 트리의 간선 수)
System.out.println(N - 1);
}
}
}
```
### 최대 유량
```java
import java.io.*;
import java.util.*;
public class Main {
static final int MAX = 52; // 알파벳 대소문자 총 개수 (대문자 26개, 소문자 26개)
static int[][] capacity; // 각 간선에 대한 용량을 저장할 2차원 배열
static int[][] flow; // 실제 흐르는 유량을 저장할 2차원 배열
static List<Integer>[] graph; // 그래프의 인접 리스트
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = Integer.parseInt(sc.nextLine()); // 간선의 개수 입력 받음
capacity = new int[MAX][MAX];
flow = new int[MAX][MAX];
graph = new ArrayList[MAX];
for (int i = 0; i < MAX; i++) {
graph[i] = new ArrayList<>();
}
for (int i = 0; i < N; i++) {
String line = sc.nextLine();
String[] input = line.split(" ");
int u = parse(input[0].charAt(0)); // 출발 정점
int v = parse(input[1].charAt(0)); // 도착 정점
int cap = Integer.parseInt(input[2]); // 용량
capacity[u][v] += cap; // 중복 간선 처리를 위해 용량을 누적
capacity[v][u] += cap; // 역방향 간선의 용량도 누적
graph[u].add(v);
graph[v].add(u);
}
// 최대 유량을 계산하고 출력
System.out.println(maxFlow(parse('A'), parse('Z')));
}
// 에드몬드-카프 알고리즘을 구현한 함수
static int maxFlow(int source, int sink) {
int totalFlow = 0;
while (true) {
int[] parent = new int[MAX]; // 증가 경로를 찾기 위한 부모 노드 저장 배열
Arrays.fill(parent, -1);
Queue<Integer> queue = new LinkedList<>();
queue.add(source);
while (!queue.isEmpty() && parent[sink] == -1) {
int current = queue.poll();
for (int next : graph[current]) {
// 아직 방문하지 않았고, 남은 용량이 있는 경우
if (parent[next] == -1 && capacity[current][next] - flow[current][next] > 0) {
queue.add(next);
parent[next] = current; // 경로를 구성
if (next == sink) break; // 도착지에 도달한 경우 루프 종료
}
}
}
if (parent[sink] == -1) break; // 더 이상 증가 경로를 찾을 수 없는 경우
int amount = Integer.MAX_VALUE;
// 증가 경로에 따라 가능한 최대 유량을 찾음
for (int p = sink; p != source; p = parent[p]) {
amount = Math.min(amount, capacity[parent[p]][p] - flow[parent[p]][p]);
}
// 증가 경로에 유량을 추가
for (int p = sink; p != source; p = parent[p]) {
flow[parent[p]][p] += amount;
flow[p][parent[p]] -= amount;
}
totalFlow += amount; // 전체 유량에 추가
}
return totalFlow; // 계산된 최대 유량 반환
}
// 문자를 정수로 매핑하는 함수
static int parse(char c) {
if (c <= 'Z') return c - 'A';
return c - 'a' + 26; // 소문자인 경우
}
}
```