N個の要素を任意個のグループに分ける、分け方によってスコアが決まり、そのスコアを最大化する問題
要素が2個の場合、スコアが正なら同じグループ、負なら違うグループにすれば良い
解説を読むと逆に「与えられた集合を2つに割る」というアプローチをしていた、なるほど
全体集合からスタートしてメモ化再帰で戻りに計算
グループごとのスコア
グループごとのスコア計算
def calcScore(S):
debug("enter calcScore: S", S)
x = S
ret = 0
i = 0
while x:
if x & 1:
debug(": i", i)
for j in range(i):
if (S >> j) & 1:
debug(": i, j, M[i,j]", i, j, M[i, j])
ret += M[i, j]
x //= 2
i += 1
debug("leave calcScore: ret", ret)
return ret
groupScore = [calcScore(i) for i in range(1 << N)]
与えられた集合の部分集合列挙 python
def solve(S):
x = S
while x > 0:
print(f"{x:08b}")
x = (x - 1) & S
:
>>> solve(14)
00001110
00001100
00001010
00001000
00000110
00000100
00000010
>>> solve(10)
00001010
00001000
00000010
組み合わせるとこんな感じ。
def solve(N, M):
FULLBIT = (1 << N) - 1
def calcScore(S):
# debug("enter calcScore: S", S)
x = S
ret = 0
i = 0
while x:
if x & 1:
# debug(": i", i)
for j in range(i):
if (S >> j) & 1:
# debug(": i, j, M[i,j]", i, j, M[i, j])
ret += M[i * N + j]
x //= 2
i += 1
# debug("leave calcScore: ret", ret)
return ret
groupScore = [calcScore(i) for i in range(1 << N)]
# debug(": groupScore", groupScore)
from functools import lru_cache
@lru_cache(maxsize=None)
def sub(S):
ret = groupScore[S]
x = (S - 1) & S
while x > 0:
y = (~x) & S
v = sub(x) + sub(y)
if v > ret:
ret = v
x = (x - 1) & S
return ret
return sub(FULLBIT)
キャッシュを書き直して十分AC python
table = [None] * (1 << N)
def sub(S):
ret = table[S]
if ret != None:
return ret
ret = groupScore[S]
x = (S - 1) & S
while x > 0:
y = (~x) & S
v = sub(x) + sub(y)
if v > ret:
ret = v
x = (x - 1) & S
table[S] = ret
return ret