📙 Algorithm Solving/Java
📙[Algo] 24.04.15 알고리즘
혜덕hyeduck
2024. 4. 16. 12:19
알고리즘 문제) BOJ 20040. 사이클 게임
문제 요약
- 0부터 n-1의 번호가 부여된 고유한 점들이 N개 주어지며, 매 차례마다
- 두 점을 선택 해 선분을 이음
- 이 때 사이클이 만들어지는 순간을 찾아서 해당 몇 번째 차례에서 처음으로 만들어졌는지 출력(없다면 0 출력)
시간 제한
- 1초
입력
- 첫 번째 줄에는 점의 개수를 나타내는 정수 3 ≤ n ≤ 500,000 과 진행된 차례의 수를 나타내는 정수 3 ≤ m ≤ 1,000,000 이 주어진다
- 이어지는 m 개의 입력 줄에는 각각 i번째 차례에 해당 플레이어가 선택한 두 점의 번호가 주어진다
출력
- 사이클이 처음으로 만들어진 차례의 번호를 양의 정수로 출력
- m 번의 차례를 모두 처리한 이후에도 종료되지 않았다면 0을 출력
코드
import java.io.*;
import java.util.*;
public class Main {
static int N, M;
static int[] parent;
static int find(int x) {
if (parent[x] == x) return x;
parent[x] = find(parent[x]);
return parent[x];
}
static void union(int a, int b) {
a = find(a);
b = find(b);
if (a == b) return;
parent[b] = a;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
parent = new int[N + 1];
for (int i = 0; i < N + 1; i++) {
parent[i] = i;
}
int a, b;
int answer = 1;
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
a = Integer.parseInt(st.nextToken());
b = Integer.parseInt(st.nextToken());
if (find(a) == find(b)) {
bw.write(String.valueOf(answer));
break;
}
union(a, b);
answer++;
}
if (answer > M) bw.write("0");
bw.flush();
bw.close();
br.close();
}
}
알고리즘 문제) BOJ 1504. 특정한 최단 경로
문제 요약
- 무방향 그래프가 주어짐
- 1번 정점에서 N번 정점으로 최단 거리로 이동하려고 함
- 한번 이동했던 정점은 물론, 한번 이동했던 간선도 다시 이동할 수 있다
- 1번 정점에서 N번 정점으로 이동할 때, 주어진 두 정점을 반드시 거치면서 최단 경로로 이동하는 프로그램을 작성
시간 제한
- 1초
입력
- 정점의 개수 N과 간선의 개수 E
- (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000)
- 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존재하며, 그 거리가 c라는 뜻
- (1 ≤ c ≤ 1,000)
- 다음 줄에는 반드시 거쳐야 하는 두 개의 서로 다른 정점 번호 v1과 v2가 주어진다. (v1 ≠ v2, v1 ≠ N, v2 ≠ 1)
- 임의의 두 정점 u와 v사이에는 간선이 최대 1개 존재
출력
- 첫째 줄에 두 개의 정점을 지나는 최단 경로의 길이를 출력
- 그러한 경로가 없을 때에는 -1을 출력
접근법
- 아래 두 가지 케이스가 존재
- 1에서 v1으로 갈 수 있는 최단 경로 + v1에서 v2로 갈 수 있는 최단 경로 + v2에서 N으로 갈 수 있는 최단 경로
- 1에서 v2으로 갈 수 있는 최단 경로 + v2에서 v1로 갈 수 있는 최단 경로 + v1에서 N으로 갈 수 있는 최단 경로
코드
import java.io.*;
import java.util.*;
public class Main {
static int N, E;
static ArrayList<Node>[] list;
static int u, v;
static int[] dist;
static boolean[] visited;
static class Node implements Comparable<Node> {
int no;
int cost;
Node(int no, int cost) {
this.no = no;
this.cost = cost;
}
@Override
public int compareTo(Node o) {
return this.cost - o.cost;
}
}
static void dijks(int start) {
PriorityQueue<Node> pq = new PriorityQueue<>();
dist[start] = 0;
pq.offer(new Node(start, 0));
int cur, nxt, nc;
while (!pq.isEmpty()) {
cur = pq.poll().no;
if (visited[cur]) continue;
visited[cur] = true;
for (Node node : list[cur]) {
nxt = node.no;
nc = dist[cur] + node.cost;
dist[nxt] = Math.min(dist[nxt], nc);
pq.offer(new Node(nxt, dist[nxt]));
}
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
E = Integer.parseInt(st.nextToken());
list = new ArrayList[N + 1];
for (int i = 0; i < N + 1; i++) {
list[i] = new ArrayList<>();
}
int v1, v2, c;
for (int i = 0; i < E; i++) {
st = new StringTokenizer(br.readLine());
v1 = Integer.parseInt(st.nextToken());
v2 = Integer.parseInt(st.nextToken());
c = Integer.parseInt(st.nextToken());
list[v1].add(new Node(v2, c));
list[v2].add(new Node(v1, c));
}
st = new StringTokenizer(br.readLine());
u = Integer.parseInt(st.nextToken());
v = Integer.parseInt(st.nextToken());
int stou, stov, utov, vtou, vtoe, utoe;
dist = new int[N + 1];
Arrays.fill(dist, 1 << 30);
visited = new boolean[N + 1];
dijks(1);
stou = dist[u];
stov = dist[v];
Arrays.fill(visited, false);
Arrays.fill(dist, 1 << 30);
dijks(u);
utov = dist[v];
utoe = dist[N];
Arrays.fill(visited, false);
Arrays.fill(dist, 1 << 30);
dijks(v);
vtou = dist[u];
vtoe = dist[N];
int dist1 = stou + utov + vtoe;
int dist2 = stov + vtou + utoe;
boolean check1 = true;
boolean check2 = true;
if (stou == 1 << 30 || utov == 1 << 30 || vtoe == 1 << 30) {
check1 = false;
}
if (stov == 1 << 30 || vtou == 1 << 30 || utoe == 1 << 30) {
check2 = false;
}
if (!check1 && check2) {
bw.write(String.valueOf(dist2));
} else if (check1 && !check2) {
bw.write(String.valueOf(dist1));
} else if (check1 && check2) {
bw.write(String.valueOf(Math.min(dist1, dist2)));
} else {
bw.write("-1");
}
bw.flush();
bw.close();
br.close();
}
}