문제


https://www.acmicpc.net/problem/2111


풀이


선인장이란 연결된 무향 그래프의 일종으로, 모든 간선이 최대 한 개의 사이클에만 속할 수 있는 그래프이다.

Cactus? Not cactus?에서 나온 선인장의 정의와는 약간 다르다.

이전 정의가 노드에 관한 것이었다면 이번 정의는 엣지에 관한 것이다.

이 정의가 조금 더 통용되는 것 같다.

새로운 선인장의 정의를 기준으로 그래프가 선인장인지 아닌지 판별하려면 약간의 조작만 거치면 된다.

visit_node 배열과 visit_edge 배열을 따로 만들어 dfs 시 몇 번 지나갔는지 카운팅 해준다.

그러다가 2번 이상 카운팅 된 엣지가 발견될 시 선인장이 아니라는 결론을 내릴 수 있다.

추가로 서브그래프의 개수를 리턴해야 되는데, 이는 $ \prod $ (사이클을 이루는 엣지의 개수 + 1)임을 쉽게 알 수 있다.


코드


import sys
from collections import defaultdict
sys.setrecursionlimit(10 ** 5)

n, m = map(int, sys.stdin.readline().split())

graph = [[] for _ in range(n + 1)]
for _ in range(m):
    edges = list(map(int, sys.stdin.readline().split()))
    for k in range(1, edges[0]):
        graph[edges[k]].append(edges[k + 1])
        graph[edges[k + 1]].append(edges[k])


def dfs(cur, par):
    global idx, ans
    dfsn[cur] = idx
    visit_node[cur] += 1
    parent[cur] = par
    idx += 1

    for nxt in graph[cur]:
        if (nxt == par) | (dfsn[nxt] >= dfsn[cur]):
            continue

        if visit_node[nxt]:
            res = 1
            temp1 = cur
            temp2 = nxt
            while temp1 != parent[nxt]:
                res += 1
                if visit_edge[temp1][temp2] == 2:
                    print(0)
                    exit()

                visit_edge[temp1][temp2] += 1
                temp2 = temp1
                temp1 = parent[temp1]
            ans *= res
        else:
            visit_edge[cur][nxt] += 1
            dfs(nxt, cur)


dfsn = [0] * (n + 1)
visit_node = [0] * (n + 1)
visit_edge = [defaultdict(int) for _ in range(n + 1)]
parent = [0] * (n + 1)
idx = 1
ans = 1

dfs(1, -1)

dfsn[0] = 1
if 0 in dfsn:
    print(0)
else:
    print(ans)

노드가 2만 개, 간선이 4만 개 일 때도 들어올 수 있어서 pypy3은 MLE가 뜬다.

python3는 스무스하게 통과하는데, 난이도 기여를 보니 다른 언어들은 큰 수 연산을 하는 데 어려움이 있었다고 한다.

Leave a comment