题解:子矩阵(NOIP2014普及组T4)

又是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 }

 

转载于:https://www.cnblogs.com/Aze-qwq/p/9879711.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值