LoginSignup
3
3

More than 1 year has passed since last update.

【競プロ典型90問】012の解説(python)

Posted at

概要

競プロ典型90問の解説記事です。
解説の画像を見ても分からない(理解力が足りない)ことが多々あったので、後で解き直した際に確認できるようまとめました。

問題012-Score Sum Queries

問題概要

白で塗られたH×Wのマス目に対して、以下の2パターンのいずれかのQ個のクエリを処理する。
1. 白いマス(r, c)を赤で塗る
2. (r1, c1), (r2, c2)の2点が与えられた時、以下の条件をどちらも満たしているか判定する
- 2点が共に赤く塗られている
- 2点が赤いマスを辿っていけば、連結している

解き方

この問題は、Union-Findを知っているか知らないかの問題です。
一応、簡単に説明すると、Union-Findとは、グループ分けの管理を非常に高速に実装できるデータ構造で、
ある集合のグループ分けや、同じグループに属しているかなどを高速に判定することができます。
Union-Findについての詳細は、ぜひ以下のスライドなどをご参照ください。

Union-Find
引用元:Union find(素集合データ構造) from Atcoder Inc.

Union-Findを用いると、各クエリの処理は以下のように、考えられます。
1. 白いマス(r, c)を赤で塗る
→ 白いマスを赤で塗り、隣接しているマスに赤いマスがあれば、連結させる。

2. (r1, c1), (r2, c2)の2点が与えられた時、赤いマスを辿っていけば、2点が連結している
→ 同じグループに属しているかを判定する

ここまで、手順が分かったので、以下で実際に実装していきたいと思います。

参考画像

引用元:競プロ典型90問 Github

実装

answer.py

# 入力の受け取り
H, W = map(int, input().split())
Q = int(input())

# 二次元配列を一次元化する関数
def flatten(h, w):
  return h+(H+1)*w

# 赤塗りかどうかを判定する配列。配列の要素数をnに格納。
M = [False]*((H+1)*W)
n = len(M)

# UnionFindの実装例
class UnionFind():
  def __init__(self, n):
      self.n = n
      self.parents = [-1] * n

  def find(self, x):
    if self.parents[x] < 0:
      return x
    else:
      self.parents[x] = self.find(self.parents[x])
      return self.parents[x]

  def union(self, x, y):
    x = self.find(x)
    y = self.find(y)

    if x == y:
      return

    if self.parents[x] > self.parents[y]:
      x, y = y, x

    self.parents[x] += self.parents[y]
    self.parents[y] = x


  def same(self, x, y):
    return self.find(x) == self.find(y)

# 要素数nを入れて、Union Findのインスタンスを作成。
uf = UnionFind(n)


for _ in range(Q):
  q = list(map(int, input().split()))

# ti = 1の時、[r, c]を赤く塗り、隣接マスを探索、もし赤なら、グループを結合する。
  if q[0] == 1:
    r, c = q[1]-1, q[2]-1
    x = flatten(r, c)
    M[x] = True
    for i, j in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
      r_dash, c_dash = r+i, c+j
      y = flatten(r_dash, c_dash)
      if 0 <= r_dash < H and 0 <= c_dash < W:
        if M[y]:
          uf.union(x, y)
# ti = 2の時、[r1, c1], [r2, c2]が共に赤なら、同じグループに属するか判定。
  else:
    x = flatten(q[1]-1, q[2]-1)
    y = flatten(q[3]-1, q[4]-1)
    if M[x] and M[y] and uf.same(x, y):
      print("Yes")
    else:
      print("No")

最後に

問題の解説を読んでも他の人のコードを見てもさっぱり分からないという方の
力に少しでもなれれば幸いです。
コードの改善点やその他、ご意見、ご質問などあれば、気軽にコメントください。

ここまでお読みいただきありがとうございました。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3