트리의 중요한 조건 중 하나는 cycle이 있는지 여부이다. 우선 그래프 조건을 만족하기 때문에 cycle이 생기는지만 검사하면 된다. cycle이 생기는지 여부는 바로 앞 node를 제외하고 다음 이동할 노드가 이미 방문한 곳이라면 cycle이 생기는 것이기 때문에 dfs로 쉽게 해결할 수 있다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class Main {
static int N, M;
static ArrayList<Integer>[] list;
static boolean[] visited;
static int cnt, step = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
StringBuilder resSb = new StringBuilder();
while (true) {
cnt = 0;
step++;
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
if (N == 0 && M == 0) {
System.out.println(resSb);
return;
}
// graph 생성
list = new ArrayList[N + 1];
visited = new boolean[N + 1];
for (int i = 1; i <= N; i++) {
list[i] = new ArrayList<>();
}
// graph 입력받기
int a, b;
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
a = Integer.parseInt(st.nextToken());
b = Integer.parseInt(st.nextToken());
list[a].add(b);
list[b].add(a);
}
for (int i = 1; i <= N; i++) {
if (!visited[i]) {
// tree인 경우에만 cnt++
if (dfs(0, i)) cnt++;
}
}
// print
resSb.append(String.format("Case %d: ", step));
if (cnt == 0) {
resSb.append("No trees.\n");
} else if (cnt == 1) {
resSb.append("There is one tree.\n");
} else {
resSb.append(String.format("A forest of %d trees.\n", cnt));
}
}
}
public static boolean dfs(int before, int x) {
// tree인지 검사하기 위해 바로 이전 것을 제외하고 이미 visited 한 것을 만나면 바로 false 반환
for (int i = 0; i < list[x].size(); i++) {
int next = list[x].get(i);
if (next == before) continue;
if (visited[next]) return false;
visited[next] = true;
if (!dfs(x, next)) return false;
}
return true;
}
}
트리의 사이클을 판단하는 문제는 자주 나오는데 많이 풀어봐야겠다.