D - Make 2-Regular Graph Editorial by sounansya


すべての頂点の次数が \(2\) である単純無向グラフと入力で与えられる \(G\) の辺の共通部分の個数の最大値を \(K\) とすると、求める答えは \(N+M-2K\) となります。したがって、この \(K\) の値を求めることを考えます。

ある頂点集合を決め打った時、その頂点集合からなるサイクルと \(G\) の辺の共通部分の個数の最大値を bitDP で求めることを考えます。サイクルは番号が最も小さい頂点 \(k\) を一つ決め打ち、そこから \(N+1-k\) 頂点のみを考えることで bitDP ができます。

最終的な答えは \(S_1 \cup S_2 \cup \ldots \cup S_c = \lbrace 1,2,\ldots,N\rbrace\) を満たす互いに素な集合 \(S_1,S_2,\ldots,S_c\) 全てに対する \(d[S_1]+d[S_2]+\ldots+d[S_c]\) の最小値(ただし \(d[S]\) は上の bitDP を考えた際のサイクル \(S\)\(G\) の辺の共通部分の個数の最大値)となります。

詳しくは実装例を参考にしてください。

計算量は \(O(N^22^N+3^N)=O(3^N)\) です。

実装例(Python3)

n, m = map(int, input().split())
g = [[False] * n for _ in range(n)]
for _ in range(m):
    a, b = map(int, input().split())
    a, b = a - 1, b - 1
    g[a][b] = True
    g[b][a] = True
INF = 100
dp = [-INF] * (1 << n)
dp[0] = 0
for st in range(n - 2):
    nn = n - st
    d = [[-INF] * (1 << (nn - 1)) for _ in range(nn)]
    d[0][0] = 0
    for s in range(1 << (nn - 1)):
        for i in range(nn):
            if d[i][s] == -INF:
                continue
            for j in range(1, nn):
                ss = s | (1 << (j - 1))
                if ss == s:
                    continue
                d[j][ss] = max(d[j][ss], d[i][s] + g[i + st][j + st])
            if i == 0 or s == (1 << (i - 1)):
                continue
            ss = ((s << 1) | 1) << st
            dp[ss] = max(dp[ss], d[i][s] + g[i + st][st])
for s in range(1 << n):
    t = s
    while t:
        dp[s] = max(dp[s], dp[t] + dp[t ^ s])
        t = (t - 1) & s
print(n + m - 2 * dp[-1])

posted:
last update: