题意
给你一个 \(n\times m(n\leq 16)\) 的矩阵,你可以调整行的顺序,然后一列一列、从上到下依次对每个元素编号
设 \(k\leq |s_i-s_{i+1}|\),要求 \(k\) 的最大值。
思路
首先预处理一下任意两行对应位置元素之差绝对值的最大值,
还有第一行和最后一行这种特殊位置的绝对值之差的最大值
然后发现暴力全排列会超时
因为 \(n\) 很小所以可以状压,
我设 f[17][17][200000] 为满足首行选的编号,当前行所选编号,已选编号的最大的最小差值绝对值 其实首行编号完全可以不用去记的
然后就可以跑记忆化搜索了,动归太难写了
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int MAXN=1e4+10;
int n,m,mt[20][MAXN];
int as[20][20],bs[20][20],ans;
int f[17][17][200000];
inline int dfs(int pos,int first,int last,int stu){
if(pos==n+1){
return bs[first][last];
}
if(f[first][last][stu]!=-1) return f[first][last][stu];
for(int i=1;i<=n;i++){
if((stu&(1<<i))==0){
f[first][last][stu]=max(f[first][last][stu],min(dfs(pos+1,first,i,stu|(1<<i)),as[i][last]));
}
}
return f[first][last][stu];
}
int main(){
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
memset(as,0x3f,sizeof(as));
memset(bs,0x3f,sizeof(bs));
memset(f,-1,sizeof(f));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mt[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=m;k++){
as[i][j]=min(as[i][j],abs(mt[i][k]-mt[j][k]));
if(k<m) bs[i][j]=min(bs[i][j],abs(mt[i][k+1]-mt[j][k]));
}
for(int i=1;i<=n;i++)
ans=max(ans,dfs(2,i,i,1<<i));
cout<<ans<<endl;
return 0;
}