题目

题目描述

给出如下定义:
     1. 子矩阵: 从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序) 被称为原矩阵的一个子矩阵。
      例如,下面左图中选取第 2、 4 行和第 2、 4、 5 列交叉位置的元素得到一个 2*3 的子矩阵如右图所示。

2. 相邻的元素:矩阵中的某个元素与其上下左右四个元素(如果存在的话)是相邻的。
3. 矩阵的分值: 矩阵中每一对相邻元素之差的绝对值之和。

本题任务:给定一个 n 行 m 列的正整数矩阵,请你从这个矩阵中选出一个 r 行 c 列的子矩阵,使得这个子矩阵的分值最小,并输出这个分值。

输入

输入文件名为 submatrix.in。
第一行包含用空格隔开的四个整数 n, m, r, c,意义如问题中所述,每两个整数之间用一个空格隔开。
接下来的 n 行, 每行包含 m 个用空格隔开的整数,用来表示问题中那个 n 行 m 列的矩阵。

输出

输出文件名为 submatrix.out。
输出共 1 行,包含 1 个整数,表示满足题目描述的子矩阵的最小分值。

样例

样例输入

样例输出

5 5 2 3
9 3 3 3 9
9 4 8 7 4
1 7 4 6 6
6 8 5 6 9
7 4 5 6 1
6
7 7 3 3
7 7 7 6 2 10 5
5 8 8 2 1 6 2
2 9 5 5 6 1 7
7 9 3 6 1 7 8
1 9 1 4 7 8 8
10 5 9 1 1 8 10
1 3 1 5 4 8 6
16

数据范围

对于 50%的数据, 1 ≤ m≤ 12 , 1 ≤n ≤ 12 , 矩阵中的每个元素 1 ≤ a [i , j] ≤20;
对于 100%的数据, 1 ≤m ≤ 16 , 1 ≤ n≤ 16 , 矩阵中的每个元素 1 ≤ a [i , j] ≤1000,1 ≤ r<=n ,1<=c<=m

提示

【输入输出样例 1 说明】
该矩阵中分值最小的 2 行 3 列的子矩阵由原矩阵的第 4 行、第 5 行与第 1 列、第 3 列、第 4 列交叉位置的元素组成,为


其分值为 |6 − 5 | +  |5 − 6 | + | 7 − 5 | +  |5 − 6 | + |6 − 7  |+ | 5 − 5 | + | 6 − 6 | = 6。

【输入输出样例 2 说明】
该矩阵中分值最小的 3 行 3 列的子矩阵由原矩阵的第 4 行、第 5 行、第 6 行与第 2 列、第 6 列、第 7 列交叉位置的元素组成, 选取的分值最小的子矩阵为

题目大意

给你一个矩阵,从中选出r行和c列,让这r行和c交叉的元素构成的矩阵的分值最小。

算法

这道题我们使用暴力+动态规划的方法。

我们先用深搜枚举选出r行。

设d[j]表示第j列所有被选中的元素上下作差得到的分值。

for (int j=1; j<=m; j++)
{int p=n+1;for (int i=1; i<=n; i++) if (vis[i]){p=i;break;}for (int i=p+1; i<=n; i++) if (vis[i]){d[j]+=abs(a[i][j]-a[p][j]);p=i;}
}

设sum[i][j]表示第i列和第j列被选中的元素左右作差得到的分值。

for (int i=1; i<=m; i++)for (int j=i+1; j<=m; j++)for (int k=1; k<=n; k++) if (vis[k])sum[i][j]+=abs(a[k][i]-a[k][j]);

设f[i][j]表示前i列,选了j列的最小分值。

是不是很像背包问题?

然后我们发现一列数的分值其实是每两个相邻的数的差的绝对值的和,即d[i]。

经过观察我们可以发现新加进一列,分值就会加上它本身的分值和它与前一列的分值。于是状态转移方程就很容易推出来了:

f[i][j]=min{f[k][j-1]+sum[k][i]}+d[i] (j-1<=k<i)

最后的ans就是

ans=min{f[i][c]} (c<=i<=m); 

代码

#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int min(int a,int b);const int INF=0x7fffffff/3;
const int N=20;
int a[N][N],f[N][N],sum[N][N],d[N];
bool vis[N];
int n,m,r,c,ans=INF;void dp()
{memset(d,0,sizeof d);memset(sum,0,sizeof sum);for (int j=1; j<=m; j++){int p=n+1;for (int i=1; i<=n; i++) if (vis[i]){p=i;break;}for (int i=p+1; i<=n; i++) if (vis[i]){d[j]+=abs(a[i][j]-a[p][j]);p=i;}}for (int i=1; i<=m; i++)for (int j=i+1; j<=m; j++)for (int k=1; k<=n; k++) if (vis[k])sum[i][j]+=abs(a[k][i]-a[k][j]);for (int i=1; i<=m; i++)for (int j=1; j<=c; j++){f[i][j]=INF;for (int k=j-1; k<i; k++) f[i][j]=min(f[i][j],f[k][j-1]+sum[k][i]);f[i][j]+=d[i];}for (int i=c; i<=m; i++) ans=min(ans,f[i][c]);
}void dfs(int k,int s)
{if (s>r) {dp();return;}if (k>n) return;vis[k]=true;dfs(k+1,s+1);vis[k]=false;dfs(k+1,s);
}int main()
{freopen("submatrix.in","r",stdin);freopen("submatrix.out","w",stdout);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",&a[i][j]);dfs(1,1);printf("%d",ans);return 0;
}int min(int a,int b)
{if (a<b) return a;else return b;
}

【NOIP2014普及组】子矩阵相关推荐

  1. 【vijos P1914】【codevs 3904】[NOIP2014 普及组T4]子矩阵(dfs+状压dp)

    P1914子矩阵 Accepted 标签:NOIP普及组2014[显示标签] 描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与 列的相对顺序)被称为原矩阵 ...

  2. 信息学奥赛一本通 1965:【14NOIP普及组】珠心算测验 | 洛谷 P2141 [NOIP2014 普及组] 珠心算测验

    [题目链接] ybt 1965:[14NOIP普及组]珠心算测验 洛谷 P2141 [NOIP2014 普及组] 珠心算测验 [题目考点] 1. 枚举 [解题思路] 解法1:枚举判断每个数字是否是加和 ...

  3. 信息学奥赛一本通 1967:【14NOIP普及组】螺旋矩阵 | 洛谷 P2239 [NOIP2014 普及组] 螺旋矩阵

    [题目链接] ybt 1967:[14NOIP普及组]螺旋矩阵 洛谷 P2239 [NOIP2014 普及组] 螺旋矩阵 类似考题: 洛谷 P1014 [NOIP1999 普及组] Cantor 表 ...

  4. [NOIP2014 普及组] 珠心算测验

    [NOIP2014 普及组] 珠心算测验 题目描述 珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术.珠心算训练,既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普及. ...

  5. P2141 [NOIP2014 普及组] 珠心算测验————C++

    题目 [NOIP2014 普及组] 珠心算测验 题目描述 珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术.珠心算训练,既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普 ...

  6. 子矩阵(NOIP2014 普及组第四题)

    描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与 列的相对顺序)被称为原矩阵的一个子矩阵. 例如,下面左图中选取第 2.4 行和第 2.4.5 列交叉位置 ...

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

    又是dp 暴力枚举会T 考虑先固定一个变量,比如先枚举行 然后预处理每行之间的绝对值,每列之间的绝对值 然后dp进行转移 注意记录选择的行数 转移记得加上新选的列的行之间的绝对值,即w[i], 1 # ...

  8. cogs luogu 珠心算测试【noip2014 普及组】

    1809. [NOIP2014]珠心算测试 ★   输入文件:countb.in   输出文件:countb.out   简单对比 时间限制:1 s   内存限制:256 MB [题目描述] [提示] ...

  9. NOIP2014普及组复赛T3——螺旋矩阵

    题目描述 一个n行n列的螺旋矩阵可由如下方法生成: 从矩阵的左上角(第1行第1列)出发,初始时向右移动:如果前方是未曾经过的格子,则继续前进,否则右转:重复上述操作直至经过矩阵中所有格子. 根据经过顺 ...

最新文章

  1. 再论JavaScript原型继承和对象继承
  2. linux 命令提示符 时间,在LINUX的命令提示符及CMD命令提示符中显示时间
  3. Failed to create the Java Virtual Machine
  4. 异常体系----java
  5. oracle 10g分区表,oracle10g-11gR2 分区表汇总一
  6. zedboard板子上呼吸灯的实现(第一版)
  7. 设计模式之——单例模式
  8. python123输出hello world_2-python学习——hello world
  9. java语言程序设计第三版电子书百度云_Java语言程序设计(基础篇)(原书第10版) 完整版 中文pdf扫描版[259MB]梁勇...
  10. 混淆 php,开发简单的PHP混淆器与解混淆器
  11. python计算器算法_Python数学运算入门把Python当作计算器
  12. 有哪些免费批量删除PDF文档的页码的方法
  13. MySQL 从删库到跑路
  14. asp.net web开发框架_Web前端开发必不可少的9个开源框架
  15. 程序员的双肩包,大概能装下整个宇宙!
  16. C语言中如何输出一些特殊的字符
  17. Linux上传输大于4G的文件,sz命令用不了
  18. 零基础可以学习厚涂么?
  19. 我啊,程序员啊程序员
  20. ASP.NET教育OA系统源码 教育行业OA系统源码带文档

热门文章

  1. 怎么卸载电脑中的oracle,oracle怎么完全卸载
  2. VisualSvn破解(VS2019)
  3. java.util包详解
  4. 各大公司数据结构与算法面试题解答(一)
  5. Educoder Python 计算思维训练——文件操作与异常处理
  6. 软件测试之构建测试---BVT
  7. 【Linux】工具(3)——gcc/g++
  8. 焦点损失函数 Focal Loss 与 GHM
  9. 所谓框架到底是什么?
  10. Leetcode题目分类指南(单独刷题或学习算法书籍配合使用)