이 문제는 네트워크 플로우 알고리즘을 사용해 두 도시(1번과 2번) 간 최대 왕복 횟수를 계산하는 문제였다. 핵심은 최대 유량(Maximum Flow) 알고리즘을 적용해 네트워크를 설계하고, 주어진 조건을 충족시키면서 최대 왕복 가능한 경로를 찾는 것이었다.
import java.util.*;
public class Main {
static final int INF = 987654321; // 무한대 값 설정
static int cityNum, pathNum, vertexNum;
static int[][] capacity, flow;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
cityNum = sc.nextInt();
pathNum = sc.nextInt();
vertexNum = (cityNum + 1) * 2; // in, out 노드를 포함한 총 정점 수
capacity = new int[vertexNum][vertexNum];
flow = new int[vertexNum][vertexNum];
// 각 도시의 in -> out 용량 1 설정
for (int i = 2; i < vertexNum; i += 2) {
capacity[i][i + 1] = 1;
}
// 간선 입력
for (int i = 0; i < pathNum; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
int uIn = u * 2, uOut = uIn + 1;
int vIn = v * 2, vOut = vIn + 1;
// u -> v, v -> u의 간선 생성
capacity[uOut][vIn] = INF;
capacity[vOut][uIn] = INF;
}
int sourceOut = (1 * 2) + 1; // 1번 도시의 out 노드
int sinkIn = (2 * 2); // 2번 도시의 in 노드
System.out.println(maximumFlow(sourceOut, sinkIn));
}
// 최대 유량 계산 (에드몬드-카프 알고리즘)
static int maximumFlow(int source, int sink) {
int totalFlow = 0;
while (true) {
int[] parent = new int[vertexNum];
Arrays.fill(parent, -1);
Queue<Integer> queue = new LinkedList<>();
parent[source] = source;
queue.add(source);
// BFS로 증가 경로 탐색
while (!queue.isEmpty() && parent[sink] == -1) {
int u = queue.poll();
for (int v = 2; v < vertexNum; v++) {
if (capacity[u][v] - flow[u][v] > 0 && parent[v] == -1) {
queue.add(v);
parent[v] = u;
}
}
}
// 증가 경로가 없는 경우 종료
if (parent[sink] == -1) {
break;
}
// 경로 상의 최소 잔여 용량 계산
int amount = INF;
for (int p = sink; p != source; p = parent[p]) {
amount = Math.min(capacity[parent[p]][p] - flow[parent[p]][p], amount);
}
// 잔여 용량을 업데이트
for (int p = sink; p != source; p = parent[p]) {
flow[parent[p]][p] += amount;
flow[p][parent[p]] -= amount;
}
totalFlow += amount;
}
return totalFlow;
}
}
capacity = new int[vertexNum][vertexNum];
flow = new int[vertexNum][vertexNum];
for (int i = 2; i < vertexNum; i += 2) {
capacity[i][i + 1] = 1; // 각 도시의 in -> out 용량 1 설정
}
for (int i = 0; i < pathNum; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
int uIn = u * 2, uOut = uIn + 1;
int vIn = v * 2, vOut = vIn + 1;
capacity[uOut][vIn] = INF; // u -> v 용량 무한대
capacity[vOut][uIn] = INF; // v -> u 용량 무한대
}
while (true) {
int[] parent = new int[vertexNum];
Arrays.fill(parent, -1);
Queue<Integer> queue = new LinkedList<>();
parent[source] = source;
queue.add(source);
while (!queue.isEmpty() && parent[sink] == -1) {
int u = queue.poll();
for (int v = 2; v < vertexNum; v++) {
if (capacity[u][v] - flow[u][v] > 0 && parent[v] == -1) {
queue.add(v);
parent[v] = u;
}
}
}
if (parent[sink] == -1) {
break; // 증가 경로가 없는 경우 종료
}
int amount = INF;
for (int p = sink; p != source; p = parent[p]) {
amount = Math.min(capacity[parent[p]][p] - flow[parent[p]][p], amount);
}
for (int p = sink; p != source; p = parent[p]) {
flow[parent[p]][p] += amount;
flow[p][parent[p]] -= amount;
}
totalFlow += amount;
}
이 문제는 네트워크 플로우를 활용해 도시 간 왕복 횟수를 계산하는 문제로, 최대 유량 알고리즘을 효율적으로 설계하는 것이 핵심이었다.