PKU 2288 Islands and Bridges
問題
n頂点からなる無向グラフが与えられる。
頂点にはそれぞれ値x[i]がついている。
このグラフのハミルトンパス(全ての頂点を1度ずつ通るパス)のうち、
次のスコアを最大にするパスのスコアおよび、総数を出力せよ。
ハミルトンパスが存在しないときは0 0を出力せよ。
スコア:
ハミルトンパスをc1,c2,c3...,cnとする。
頂点ciの値をv[i]とするとき、スコアは次の式で与えられる。
Σv[i] + Σv[i] * v[i - 1] + Σ[ciとci-2の間に辺があるi]v[i] * v[i - 1] * v[i - 2]
制約条件
n≦13
v[i]≦100
逆順にして重なるパスは同一とみなす。
方針
dp[mask][i][j]を、今までにmaskの都市を訪問して、現在iにいて、直前にjにいたときの
今までのスコアの最大値とするようなビットDPをすればよい。
同時にway[mask][i][j]も使って場合の数も求めてやる。
逆順のパスも数えてしまっているので、全体を2で割る。
ただしn = 1のときはコーナーケースで、このときは2で割らない。
ソースコード
int n, m, v[20]; bool e[20][20]; int dp[1 << 13][13][13]; ll way[1 << 13][13][13]; int main(){ int cs; cin >> cs; while(cs--){ cin >> n >> m; rep(i, n) rep(j, n) e[i][j] = 0; rep(i, n) cin >> v[i]; rep(i, m){ int x, y; cin >> x >> y; e[--x][--y] = 1; e[y][x] = 1; } rep(i, 1 << n) rep(j, n) rep(k, n) dp[i][j][k] = -1e9, way[i][j][k] = 0; rep(i, n) dp[1 << i][i][i] = 0, way[1 << i][i][i] = 1; rep(i, 1 << n) rep(j, n) rep(k, n) if(way[i][j][k]) rep(l, n){ if((i & 1 << l) || !e[j][l]) continue; int ni = i | 1 << l, nc = dp[i][j][k] + v[j] * v[l]; if(j != k && e[k][l]) nc += v[j] * v[k] * v[l]; if(dp[ni][l][j] < nc) dp[ni][l][j] = nc, way[ni][l][j] = 0; if(dp[ni][l][j] == nc) way[ni][l][j] += way[i][j][k]; } int ans = 0; ll cnt = 0; rep(i, n) rep(j, n){ if(ans < dp[(1 << n) - 1][i][j]) ans = dp[(1 << n) - 1][i][j], cnt = 0; if(ans == dp[(1 << n) - 1][i][j]) cnt += way[(1 << n) - 1][i][j]; } if(cnt) rep(i, n) ans += v[i]; if(n == 1) cnt = 2; cout << ans << " " << cnt / 2 << endl; } return 0; }