给出如下定义:
1. 子矩阵: 从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与 列的相对顺序) 被称为原矩阵的一个子矩阵。
例如,下面左图中选取第 2、 4 行和第 2、 4、 5 列交叉位置的元素得到一个 2*3 的子矩 阵如右图所示。
- 相邻的元素:矩阵中的某个元素与其上下左右四个元素(如果存在的话)是相邻的。
- 矩阵的分值: 矩阵中每一对相邻元素之差的绝对值之和。
本题任务:给定一个 n 行 m 列的正整数矩阵,请你从这个矩阵中选出一个 r 行 c 列的 子矩阵,使得这个子矩阵的分值最小,并输出这个分值。
c++解法:
-
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; int i,m,n,j,k,a[20][20],b[20][20],r,c,d[20],w[20],f[20][20],ans=0x3f3f3f3f; void dp() { memset(w,0,sizeof(w)); memset(b,0,sizeof(b)); memset(f,0x3f,sizeof(f)); for(int i=1;i<=m;i++) for(int j=2;j<=r;j++) w[i]+=abs(a[d[j]][i]-a[d[j-1]][i]); for(int i=1;i<m;i++) for(int j=i+1;j<=m;j++) for(int l=1;l<=r;l++) b[i][j]+=abs(a[d[l]][i]-a[d[l]][j]); f[0][0]=0; for(int i=1;i<=m;i++) for(int j=1;j<=min(i,c);j++) for(int l=j-1;l<i;l++) f[i][j]=min(f[i][j],f[l][j-1]+b[l][i]+w[i]); for(int i=c;i<=m;i++) ans=min(ans,f[i][c]); } void dfs(int k,int now) { if(k==r) {dp(); return;} for(int i=now;i<=n-r+k+1;i++) d[k+1]=i,dfs(k+1,i+1); } int main() { scanf("%d%d%d%d",&n,&m,&r,&c); for(i=1;i<=n;i++) for(j=1;j<=m;j++) scanf("%d",&a[i][j]); dfs(0,1); printf("%d",ans); }