1. 程式人生 > >題解:子矩陣(NOIP2014普及組T4)

題解:子矩陣(NOIP2014普及組T4)

+= out bsp tdi 又是 style 預處理 sizeof 表示

又是dp

暴力枚舉會T

考慮先固定一個變量,比如先枚舉行

然後預處理每行之間的絕對值,每列之間的絕對值

然後dp進行轉移

註意記錄選擇的行數

轉移記得加上新選的列的行之間的絕對值,即w[i],

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 using namespace std;
 6 int n, m, r, c;
 7 int a[20][20], f[20][20];//f[i][j]表示選擇了i列,最後一列為j
8 int w[20], v[20][20], path[20]; 9 int ans=1<<30; 10 void work(){ 11 memset(f,127,sizeof(f)); 12 memset(w,0,sizeof(w)); 13 memset(v,0,sizeof(v)); 14 for(int i=1; i<=m; i++) 15 for(int j=1; j<r; j++) 16 w[i]+=abs(a[path[j]][i]-a[path[j+1]][i]); //
記錄已選擇的行之間第i列的絕對值 17 for(int i=1; i<=m; i++) 18 for(int j=i+1; j<=m; j++) 19 for(int k=1; k<=r; k++) 20 v[i][j]+=abs(a[path[k]][i]-a[path[k]][j]); //預處理每列之間的絕對值差 21 f[0][0]=0; 22 for(int i=1; i<=c; i++) 23 for(int j=i; j<=m; j++)
24 for(int k=0; k<j; k++) 25 f[i][j]=min(f[i][j], f[i-1][k]+w[j]+v[k][j]);//dp 26 for(int i=c; i<=m; i++) ans=min(ans, f[c][i]); //尋找答案 27 28 } 29 void dfs(int now, int pre){ 30 if(now>r){ 31 work(); 32 return ; 33 } 34 for(int i=pre+1; n-i>=r-now; i++){ 35 path[now]=i; 36 dfs(now+1, i); 37 } 38 } 39 int main(){ 40 scanf("%d%d%d%d",&n,&m,&r,&c); 41 for(int i=1; i<=n; ++i) 42 for(int j=1; j<=m; ++j) 43 scanf("%d",&a[i][j]); 44 dfs(1, 0); 45 cout<<ans<<endl; 46 return 0; 47 }

題解:子矩陣(NOIP2014普及組T4)