この課題は1年以上前のものですが、「未回答」でこれを見つけただけで、非常に興味深く見えました。
「ルート」セルの番号が各地域で唯一の重要な番号であると仮定すると(例から推測できます)、ここに私のバックトラッキングソリューションがあります。
from itertools import*
def f(a):
D=len(a[0])+1;S={D*r+c for r in range(len(a))for c in range(D-1)if a[r][c]};s=[{x,*t}for x in S for t in combinations({x-D,x-1,x+1,x+D}&S,a[x//D][x%D]-1)]
def B(s,S,d=1):
if{0}>S:return a
if[]==s:return 0
h,*t=s
if h<=S:
for x in h:a[x//D][x%D]=d
return h<=S and B(t,S-h,d+1)or B(t,S,d)
return B(s,S)
オンラインでお試しください!
入力形式は整数の2Dリストで、空白はゼロであり、出力形式も数値ごとに1つの領域を表す整数の2Dリストです。リージョン番号は1から始まります。ゼロは空白セル用に予約されています(入力の場合)。指定された入力が解決できない場合、関数は単一のゼロ(偽の値)を返します。
たとえば、テストケース5は次のように入力されます。
[[2,3,2],
[3,4,3],
[0,4,0],
[3,3,3],
[2,3,2],
[0,3,0]]
そして出力は
[[1,1,1],
[2,2,2],
[0,2,0],
[3,4,5],
[3,4,5],
[0,4,0]]
Ungolfed、コメント付き:
from itertools import*
def f(a):
# Rows, cols, fake-cols to prevent neighbors wrap around
R,C=len(a),len(a[0]);D=C+1
# All valid cells represented as integers
S={D*r+c for r in range(R) for c in range(C) if a[r][c]}
# All valid regions rooted at each cell
s=[{x,*t} for x in S for t in combinations({x-D,x-1,x+1,x+D}&S,a[x//D][x%D]-1)]
# Start backtracking
return backtrack(a,s,S,D)
# a: array to fill in the region numbers
# s: current candidates of regions
# S: current remaining cells to cover
# D: constant from f
# d: recursion depth == group number in the result
def backtrack(a,s,S,D,d=1):
# Empty S: the board is correctly covered, return the result
if not S:return a
# Empty s: no more candidate regions to use, return false
if not s:return 0
h,*t=s
# h is not a subset of S: h is not a valid cover, try with the rest using same depth
if not h<=S:return backtrack(a,t,S,D,d)
# h is a valid cover, write d to the cells in h
for x in h:a[x//D][x%D]=d
return backtrack(a,t,S-h,D,d+1)or backtrack(a,t,S,D,d)
オンラインでお試しください!
注:これは、NP完全であることがよく知られているセットパッキングの特殊なケースです。この特定の問題はセットサイズ(最大4)を制限し、多項式時間で「適切な」セットパッキングを見つける近似アルゴリズムが存在しますが、可能な限り最大のセットパッキングを保証しません(この問題では厳密に必要です)。
4
、それらが有効な入力である場合にも対応する必要があります。