在矩阵中求解最优情况,其中$n \leq 16$
假设现在已经得到保留的行与列的编号,递推矩阵分值的复杂度是$O(n^2)$遍历一遍就ok
50pts 假设行列全部枚举全排列的话,枚举次数在最坏情况下是$(C_{12}^6)^2=924^2$,在加上求分值的复杂度则总复杂度还是勉强可以接受的?
直接看100pts解法,仍然枚举一次行的全排列,复杂度是$O(C_m^c)$,这个时候我们得到的其实是一行数列,数列上的每个数有选择和不选择两种状态,选择每个数会增加分值,分别是:
- 自身的分数(该列上下数字差值绝对值和)
- 相对左侧(右侧)的分数,左侧和右侧的选择都会影响这种相对分数
那么提前预处理出数列上每个数两两之间相对的分数和自身的分数,因为要枚举$m$的原因,所以复杂度是$O(n^3)$
进行dp,设$f[i][l]$为已选择到数列上第$i$个数,已选择$l$个数的最大值,很明显$f[i][l]=min(f[k][l-1]+sum[k][i])$ 其中$k \subseteq[1,i-1]$,不需要太多优化,只要枚举$i,k,l$就可以在$O(n^3)$之内解决问题,该种方法总复杂度$O(C_m^c n^3)$可以通过$n=16$的数据
```
//2019/7/19->Riko->AtNCU->luoguP2258
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
bool digit (int ch) { return (ch <= ‘9‘ and ch >= ‘0‘);}
inline int in () {
int x = 0, ch = getchar(), base = 1;
while (!digit(ch)) {
if (base == ‘-‘) base = -1;
ch = getchar();
}
while (digit(ch)) x = x*10+ch-‘0‘, ch = getchar();
return x*base;
}
template <typename T> inline void smin (T& x, T y) { if (x > y) x = y;}
inline int abs (int x) { return (x < 0) ? -x : x;}
const int N = 24;
int n, m, r, c, ans, cnt;
int f[N][N], a[N][N], sum[N][N], suml[N], bol[N];
void work () {
memset(sum, 0, sizeof(sum));
memset(suml, 0, sizeof(suml));
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <= n; ++i) {
for (int j = i+1; j <= n; ++j) {
int seg = 0;
for (int l = 1; l <= m; ++l) {
if (bol[l]) seg += abs(a[i][l]-a[j][l]);
}
sum[i][j] = sum[j][i] = seg;
}
int last = 0;
for (int l = 1; l <= m; ++l) {
if (bol[l]) {
if (last) suml[i] += abs(a[i][l]-last);
last = a[i][l];
}
}
}
for (int i = 1; i <= n; ++i) { f[i][1] = suml[i];}
for (int i = 1; i <= n; ++i) {
for (int l = 2; l <= r; ++l) {
int Min = f[0][0];
for (int j = 1; j < i; ++j) {
smin(Min, f[j][l-1]+sum[j][i]);
}
f[i][l] = Min+suml[i];
}
}
for (int i = 1; i <= n; ++i) { smin(ans, f[i][r]);}
}
void dfs (int idx, int num) {
if (num == c) {
work();
return;
}
for (int i = idx; i <= m; ++i) {
bol[i] = true;
dfs(i+1, num+1);
bol[i] = false;
}
}
void prepare () {
n = in(); m = in();
r = in(); c = in();
ans = 999999999;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
a[i][j] = in();
}
}
dfs(1, 0);
printf("%d", ans);
} int main () { prepare();}
```
原文地址:https://www.cnblogs.com/NHDR233/p/11246712.html