題意 "題目鏈接" Sol $n \leqslant 16$可以想到狀壓 我們可以預處理出任意兩行之間每列的最小值以及相鄰兩列的最小值 然後枚舉一個起點,$f[sta][i]$表示走過了$sta$這個集合內的元素,當前在$i$點的$k$的最大值 轉移的時候枚舉接下來走哪個位置即可 時間複雜度$n^3 ...
題意
Sol
\(n \leqslant 16\)可以想到狀壓
我們可以預處理出任意兩行之間每列的最小值以及相鄰兩列的最小值
然後枚舉一個起點,\(f[sta][i]\)表示走過了\(sta\)這個集合內的元素,當前在\(i\)點的\(k\)的最大值
轉移的時候枚舉接下來走哪個位置即可
時間複雜度\(n^3 2^n\)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10, INF = 1e9 + 10, SS = 18;
template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M, Lim, a[SS][MAXN], f[1 << (SS)][SS], Mn[SS][MAXN], L[SS][MAXN];
void Pre() {
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= N; j++) {
Mn[i][j] = INF; L[i][j] = INF;
for(int k = 1; k <= M; k++) chmin(Mn[i][j], (i == j) ? a[i][k] : abs(a[i][k] - a[j][k]));
for(int k = 1; k < M; k++) chmin(L[i][j], abs(a[i][k] - a[j][k + 1]));
}
}
}
int DP(int bg) {
memset(f, -1, sizeof(f));
f[1 << (bg - 1)][bg] = INF;
for(int sta = 0; sta < Lim; sta++) {
for(int i = 1; i <= N; i++) {
if(f[sta][i] == -1) continue;
for(int j = 1; j <= N; j++) {
if(sta & (1 << (j - 1))) continue;
chmax(f[sta | (1 << (j - 1))][j], min(f[sta][i], Mn[i][j]));
}
}
}
int now = 0;
for(int i = 1; i <= N; i++)
chmax(now, min(f[Lim][i], L[i][bg]));
return now;
}
int main() {
N = read(); M = read(); Lim = (1 << N) - 1;
for(int i = 1; i <= N; i++)
for(int j = 1; j <= M; j++) a[i][j] = read();
Pre();
int ans = 0;
for(int i = 1; i <= N; i++)
chmax(ans, DP(i));
cout << ans;
return 0;
}
/*
3 2
85 6
64 71
1 83
4 2
9 9
10 8
5 3
4 3
*/