CodeForces 1102F. Elongated Matrix 状压Dp

传送门

题意

给你一个 (n imes m(nleq 16)) 的矩阵,你可以调整行的顺序,然后一列一列、从上到下依次对每个元素编号
(kleq |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;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/12164534.html