题解 P2258 【子矩阵】

题目大意

Solution [NOIP2014普及]子矩阵

题目大意:定义一个矩阵的分值为两两相邻元素的差的绝对值,试在一个\(n\)\(m\)列的矩阵中选出一个\(r\)\(c\)列的子矩阵(即行列交叉位置的元素),使其分值最小

题目分析:一开始拿到这道题想的是爆搜,但是分析了一下时间复杂度\(O(C_n^rC_m^c)\)怕是有点悬.找着题意\(dp\)?,四维\(dp\)写不出来在下告辞

然后就有一种神奇的做法,先\(dfs\)枚举行,然后就会得到很多\(r\)\(m\)列的矩阵,然后再用二维\(dp\)求解

\(f[i][j]\)表示前\(i\)列,当前已经选了\(j\)列的最小分值.设\(w[i]\)表示\(i\)这一列的分值,\(v[i][j]\)表示\(i,j\)这两列的分值,那么

\[f[i][j] = min\{f[k][j - 1] + w[i] + v[k][i] \quad | \quad j - 1 \leq k < i\}\]

通过一些技巧来处理可以不用复杂的\(if\)语句来考虑边界条件,让程序更加简洁.即假设有一个虚拟的第\(0\)

分析一下复杂度?枚举行为\(O(C_n^r)\),进行一次\(dp\)的成本为\(O(m^2)\)

所以总复杂度为\(O(C_n^rm^2)\),跑的过去(我常数有那么爆炸吗,吸口氧运行时间变成了原来的\(\frac{1}{4}\))

代码奉上

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 32;
int n,m,r,c,p[maxn],w[maxn],v[maxn][maxn],f[maxn][maxn],val[maxn][maxn],ans = 1e9;
inline void dp(){//进行dp
    for(int i = 1;i <= m;i++)//初始化
        for(int j = 1;j <= m;j++)
            f[i][j] = 1e9;
    for(int i = 1;i <= m;i++){//计算每一列的分值
        w[i] = 0;
        for(int j = 2;j <= r;j++)
            w[i] += abs(val[p[j]][i] - val[p[j - 1]][i]);
    }
    for(int i = 1;i <= m;i++)//初始化
        for(int j = 1;j <= m;j++)
            v[i][j] = 0;
    for(int i = 1;i <= m;i++)//计算两两列之间的分值
        for(int j = 1;j <= m;j++)
            for(int k = 1;k <= r;k++)
                v[i][j] += abs(val[p[k]][i] - val[p[k]][j]);
    for(int i = 1;i <= m;i++)//进行dp
        for(int j = 1;j <= min(i,c);j++){
            for(int k = j - 1;k < i;k++)
                    f[i][j] = min(f[i][j],f[k][j - 1] + w[i] + v[k][i]);
            if(j == c)ans = min(ans,f[i][j]);//如果已经选了r行c列了,更新答案
        }
}
inline void dfs(int line,int step){//dfs枚举行
    if(step == r + 1){
        dp();
        return;
    }
    if(line > n)return;
    p[step] = line;
    dfs(line + 1,step + 1);
    dfs(line + 1,step);
}
int main(){
    scanf("%d %d %d %d",&n,&m,&r,&c);
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
            scanf("%d",&val[i][j]);
    dfs(1,1);
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/colazcy/p/11514983.html