noip 2014 子矩阵
先枚举行再DP列。好题,详见代码
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <climits> 5 #include <vector> 6 #include <iostream> 7 using namespace std; 8 const int N=20; 9 const int inf =0x3f3f3f3f; 10 int n,m,r,c,p[N][N],v[N],f[N],res=inf,t[N],t1[N][N]; 11 12 int DP() { 13 memset(t,0,sizeof t); 14 memset(t1,0,sizeof t1); 15 for (int i=1; i<=m; i++)//预处理同一列相邻行之间的差值 16 for (int j=1; j<v[0]; j++) t[i]+=abs(p[v[j]][i]-p[v[j+1]][i]); 17 for (int i=1; i<m; i++)//处理每一列之间的差值 18 for (int j=i+1; j<=m; j++) 19 for (int k=1; k<=v[0]; k++) t1[i][j]+=abs(p[v[k]][i]-p[v[k]][j]); 20 for (int i=1; i<=m; i++) f[i]=t[i]; 21 for (int i=2; i<=c; i++)//DP主要部分 22 for (int j=m; j>=i; j--) { 23 f[j]=inf; 24 for (int k=j-1; k>=i-1; k--) f[j]=min(f[j],f[k]+t1[k][j]); 25 f[j]+=t[j]; 26 } 27 int ans=inf; 28 for (int i=c; i<=m; i++) ans=min(ans,f[i]); 29 return ans; 30 } 31 32 void DFS(int i,int dep) {//枚举行数 33 if (dep==r) { 34 res=min(res,DP()); 35 return; 36 } 37 for (int j=i; j<=n-r+dep+1; j++) { 38 v[++v[0]]=j; 39 DFS(j+1,dep+1); 40 v[v[0]--]=0; 41 } 42 } 43 44 void work() { 45 DFS(1,0); 46 printf("%d\n",res); 47 } 48 49 int main() { 50 memset(v,0,sizeof(v)); 51 scanf("%d%d%d%d",&n,&m,&r,&c); 52 for (int i=1; i<=n; i++) 53 for (int j=1; j<=m; j++) 54 scanf("%d",&p[i][j]); 55 work(); 56 return 0; 57 }