Description:
求最大权哈密尔顿回路。
Solution:
插头
裸题。
预处理出所有轮廓线的状态,令
表示第
行第
列轮廓线状态为
的最大权值。先预处理出第一行的
值,每次做到末尾时计算下一行第一格。
用三进制表示状态,
1
2
1.
2.
3.
4.
5.
6.
7.$左插头和右插头,直接接上。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m, ans = -0x3f3f3f3f;
int dp[105][7][2205], a[105][7], lp[2205][7], rp[2205][7], bin[8];
bool can[2205];
bool check(int S) {
int s = 0;
for(int i = 0; i <= n; ++i) {
if(S / bin[i] % 3 == 1) {
++s;
} else if(S / bin[i] % 3 == 2) {
--s;
}
if(s < 0) {
return 0;
}
}
return s == 0;
}
int fl(int S, int p) {
int s = 1;
for(int i = p - 1; ~i; --i) {
if(S / bin[i] % 3 == 1) {
--s;
} else if(S / bin[i] % 3 == 2) {
++s;
}
if(s == 0) {
return i;
}
}
}
int fr(int S, int p) {
int s = 1;
for(int i = p + 1; i <= n; ++i) {
if(S / bin[i] % 3 == 2) {
--s;
} else if(S / bin[i] % 3 == 1) {
++s;
}
if(s == 0) {
return i;
}
}
}
void U(int &x, int y) {
if(x < y) {
x = y;
}
}
int calc(int S) {
int ret = 0, s = 0;
for(int i = 0; i < n; ++i) {
if(S / bin[i] % 3 == 1) {
++s;
ret += a[1][i + 1];
} else if(S / bin[i] % 3 == 2) {
--s;
ret += a[1][i + 1];
} else if(s) {
ret += a[1][i + 1];
}
if(s > 1) {
return -0x3f3f3f3f;
}
}
return ret;
}
int main() {
scanf("%d%d", &m, &n);
bin[0] = 1;
for(int i = 1; i <= n + 1; ++i) {
bin[i] = bin[i - 1] * 3;
}
for(int i = 1; i <= m; ++i) {
for(int j = 1; j <= n; ++j) {
scanf("%d", &a[i][j]);
}
}
memset(dp, -0x3f3f, sizeof(dp));
for(int i = 0; i < bin[n + 1]; ++i) {
if(check(i)) {
can[i] = 1;
for(int j = 0; j <= n; ++j) {
int bit = i / bin[j] % 3;
if(bit == 1) {
rp[i][j] = fr(i, j);
} if(bit == 2) {
lp[i][j] = fl(i, j);
}
}
}
if(!(i / bin[n])) {
dp[1][n][i] = calc(i);
}
}
for(int i = 2; i <= m; ++i) {
for(int S = 0; S < bin[n + 1]; ++S) {
if(can[S] && !(S / bin[n])) {
int S0 = (S - S % 3) * 3;
if(S / bin[0] % 3 == 1) {
U(dp[i][1][S0 + 1], dp[i - 1][n][S] + a[i][1]);
U(dp[i][1][S0 + 3], dp[i - 1][n][S] + a[i][1]);
} else if(S / bin[0] % 3 == 0) {
U(dp[i][1][S0 + 7], dp[i - 1][n][S] + a[i][1]);
U(dp[i][1][S0], dp[i - 1][n][S]);
}
}
}
for(int j = 2; j <= n; ++j) {
for(int S = 0; S < bin[n + 1]; ++S) {
if(can[S]) {
int u = S / bin[j - 1] % 3, v = S / bin[j] % 3, S0 = S - bin[j - 1] * u - bin[j] * v, tmp = dp[i][j - 1][S];
if(!u && !v) {
U(dp[i][j][S0 + bin[j - 1] + 2 * bin[j]], tmp + a[i][j]);
U(dp[i][j][S0], tmp);
}
if((!u && v == 1) || (u == 1 && !v)) {
U(dp[i][j][S0 + bin[j - 1]], tmp + a[i][j]);
U(dp[i][j][S0 + bin[j]], tmp + a[i][j]);
}
if((!u && v == 2) || (u == 2 && !v)) {
U(dp[i][j][S0 + bin[j - 1] * 2], tmp + a[i][j]);
U(dp[i][j][S0 + bin[j] * 2], tmp + a[i][j]);
}
if(u == 1 && v == 1) {
U(dp[i][j][S0 - bin[rp[S][j]]], tmp + a[i][j]);
}
if(u == 2 && v == 2) {
U(dp[i][j][S0 + bin[lp[S][j - 1]]], tmp + a[i][j]);
}
if(u == 1 && v == 2) {
if(!S0) {
U(ans, tmp + a[i][j]);
}
}
if(u == 2 && v == 1) {
U(dp[i][j][S0], tmp + a[i][j]);
}
}
}
}
}
printf("%d\n", ans);
return 0;
}