結果
| 問題 |
No.3047 Verification of Sorting Network
|
| ユーザー |
👑 |
| 提出日時 | 2025-03-09 22:00:10 |
| 言語 | PyPy3 (7.3.15) |
| 結果 |
AC
|
| 実行時間 | 870 ms / 2,000 ms |
| コード長 | 6,250 bytes |
| コンパイル時間 | 621 ms |
| コンパイル使用メモリ | 81,912 KB |
| 実行使用メモリ | 107,472 KB |
| 最終ジャッジ日時 | 2025-03-09 22:00:38 |
| 合計ジャッジ時間 | 23,269 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 61 |
ソースコード
"""
yukicoder Problem: Verify Sorting Network
"""
import functools
import math
import sys
SHOW_PROGRESS_THRESHOLD = 28
UNLIMITED = True
MAX_TESTCASES = 1000
MAX_N = 27
MAX_COST = 1e8
class IsSortingOk:
"""is_sorting_network Ok type"""
def __init__(self, value: list[bool]):
self.value = value
def __bool__(self):
return True
def __str__(self):
return 'Yes'
def get_data(self):
"""get data value"""
return self.value
class IsSortingNg:
"""is_sorting_network Ng type"""
def __init__(self, value: list[bool]):
self.value = value
def __bool__(self):
return False
def __str__(self):
return 'No'
def get_error(self):
"""get error value"""
return self.value
def fib1(n: int) -> list[int]:
"""フィボナッチ数列 [1,1,2,3,…,Fib(n+1)] を生成します。"""
return functools.reduce(lambda x, _: x + [sum(x[-2:])], range(n), [1])
def is_sorting_network(n: int, net: list[tuple[int, int]]) -> IsSortingOk | IsSortingNg:
"""
与えられたネットワークが sorting network であるかどうかを調べます。
時間計算量 O(m * phi**n) で動作します。 phi は黄金比1.618...です。
n は入力の数、 m は比較器の数です。
ref: Hisayasu Kuroda. (1997). A proposal of Gap Decrease Sorting Network.
Trans.IPS.Japan, vol.38, no.3, p.381-389.
http://id.nii.ac.jp/1001/00013442/
"""
assert 2 <= n
# 0-indexed 入力の範囲を確認
assert all(0 <= a < b < n for a, b in net)
# 比較器の数
m = len(net)
# 初期状態はすべて '?' = 不定: 0 または 1 に決定されていない
stack = [((1 << n) - 1, (1 << n) - 1, 0)]
# 使われる事がある比較器かどうかを記録
unused = [True] * m
# ソートされない位置を記録
unsorted_i = 0
# レイヤー分割
net_layers: list[list[tuple[int, int, int]]] = []
net_remain: list[tuple[int, int, int]] = [(a, b, i) for i, (a, b) in enumerate(net)]
while net_remain:
layer_used = [False] * n
layer: list[tuple[int, int, int]] = []
remain_next: list[tuple[int, int, int]] = []
for a, b, i in net_remain:
if layer_used[a] or layer_used[b]:
remain_next.append((a, b, i))
else:
layer.append((a, b, i))
layer_used[a] = layer_used[b] = True
net_layers.append(layer)
net_remain = remain_next
# レイヤー毎に探索
net_p: list[tuple[int, int, int]] = []
for layer in net_layers:
# net_p += layer
net_p.extend(layer)
net_plen = len(net_p)
# 次のレイヤーのジョブの蓄積(重複した状態を除去)
stack_nextlayer: set[tuple[int, int, int]] = set()
while stack:
z, o, i = stack.pop()
while i < net_plen:
a, b, j = net_p[i]
i += 1
if ((o >> a) & 1) == 0 or ((z >> b) & 1) == 0:
pass
elif ((z >> a) & 1) == 0 or ((o >> b) & 1) == 0:
unused[j] = False
xz, xo = (((z >> a) ^ (z >> b)) & 1), (((o >> a) ^ (o >> b)) & 1)
z, o = (z ^ ((xz << a) | (xz << b))), (o ^ ((xo << a) | (xo << b)))
if (o & (z >> 1)) == 0:
break
else:
unused[j] = False
qz, qo, z = z, (o ^ (1 << a) ^ (1 << b)), (z ^ (1 << b))
if (qo & (qz >> 1)) != 0:
stack.append((qz, qo, i))
if (o & (z >> 1)) == 0:
break
else:
stack_nextlayer.add((z, o, i))
# 次のレイヤーのジョブを生成
stack = list(stack_nextlayer)
# 進捗表示
if SHOW_PROGRESS_THRESHOLD <= n:
percent = len(net_p) * 100 // len(net)
sys.stderr.write(f'{percent}%\r')
assert len(net_p) == len(net)
if SHOW_PROGRESS_THRESHOLD <= n:
sys.stderr.write('\n')
# ソートされていない位置がある場合
for z, o, i in stack:
assert i == len(net)
unsorted_i |= (o & (z >> 1))
if unsorted_i != 0:
unsorted = [((unsorted_i >> i) & 1) != 0 for i in range(n - 1)]
return IsSortingNg(unsorted)
# すべての分岐でソートされている場合
return IsSortingOk(unused)
# 黄金比 (1+sqrt(5))/2 ≒ 1.618033988749895
PHI = math.sqrt(1.25) + 0.5 # 黄金比
def main():
"""テストケースの入出力処理"""
t = int(sys.stdin.readline())
assert t <= MAX_TESTCASES or UNLIMITED
cost = 0
for _ in range(t):
n, m = map(int, sys.stdin.readline().split())
assert 2 <= n <= MAX_N or UNLIMITED
assert 1 <= m <= n * (n - 1) // 2 or UNLIMITED
cost += m * PHI**n # テストケースの計算量コスト
assert cost <= MAX_COST or UNLIMITED
# 1-indexed -> 0-indexed
a = map(lambda x: int(x) - 1, sys.stdin.readline().split())
b = map(lambda x: int(x) - 1, sys.stdin.readline().split())
cmps: list[tuple[int, int]] = list(zip(a, b))
assert len(cmps) == m
assert all(0 <= a < b < n for a, b in cmps)
# is_sorting: 与えられたネットワークが sorting network であるかどうか
is_sorting = is_sorting_network(n, cmps)
print(is_sorting) # Yes or No
if is_sorting:
# unused_cmp: 使われない比較器かどうか (is_sorting=True の場合のみ)
unused_cmp = is_sorting.get_data()
assert len(unused_cmp) == m
print(sum(unused_cmp))
print(*map(lambda e: e[0] + 1, filter(lambda e: e[1], enumerate(unused_cmp))))
else:
# unsorted_pos: ソートされない可能性のある位置 (is_sorting=False の場合のみ)
unsorted_pos = is_sorting.get_error()
assert len(unsorted_pos) == n - 1
print(sum(unsorted_pos))
print(*map(lambda e: e[0] + 1, filter(lambda e: e[1], enumerate(unsorted_pos))))
main()