ABC292 D問題 Unicyclic Components

atcoder.jp

連結成分を調べたいときは Union-Find 木

Union-Find 木 (「競技プログラミングの鉄則」 9.6 Union-Find 木) の考え方を利用します。
同じグループに属する頂点を木構造で表現することにして、頂点 x の親を parent[x] に記録していきます。
頂点番号と親の番号が同じ頂点は、グループの代表(root) になります。
最初すべての頂点について parent[i] = i で初期化して、辺で結ばれたグループを1つのグループにまとめる処理を行っていきます。

また、各頂点に属する辺の数を記録するための配列を用意して、辺を追加するたびに、その一方の頂点で数を1つずつ増やしていきます。
(二重カウントを避けるために、一方の頂点だけで数えていきます)

最後に、各頂点の root を求め、その root に頂点の数と辺の数を加算していき、頂点の数と辺の数が一致するかどうか調べます。


コード例 (Julia)

function solve()

  # 入力
  readInts() =  parse.(Int,split(readline()))
  readInt()  =  parse(Int,readline())

  N,M = readInts()

  parent = Vector{Int}(1:N)  # Union-Find tree : 親ノード番号
  n_edge = zeros(N)          # 辺の数のカウント用

  # 関数定義
  root(x) = (parent[x]==x ? x : parent[x] = root(parent[x]))
  unite(x,y) = ( root(x)!=root(y) ? ( parent[root(x)] =  root(y) ) : root(x) )

  # 辺を追加していく
  for i = 1:M
    u,v = readInts()
    unite(u,v)       # Union-Find tree でグループ結合
    n_edge[u] += 1   # 辺の数のカウント
  end

  n_node = zeros(N)  # 頂点の数のカウント用

  for i = 1:N
    r = root(i)

    n_node[r] += 1    # root に属する頂点のカウント

    if r != i
      n_edge[r] += n_edge[i]   # root に属する辺のカウント
    end
  end

  for i = 1:N
    if n_node[i] > 0
      # i を root とするグループで頂点数と辺数が一致するか調べる
      if n_node[i] != n_edge[i]  
        println("No")
        return
      end
    end
  end

  println("Yes")
  return

end  # function solve

# main
solve()