题目描述:

一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵(矩阵中元素个数为矩阵面积)

输入:

每个案例第一行三个正整数N,M<=100,表示矩阵大小,和一个整数K
接下来N行,每行M个数,表示矩阵每个元素的值

输出:

输出最小面积的值。如果出现任意矩阵的和都小于K,直接输出-1。

样例输入:
  1. 4 4 10
  2. 1 2 3 4
  3. 5 6 7 8
  4. 9 10 11 12
  5. 13 14 15 16
样例输出:
  1. 1
  2.  
  3. 这道题的题意读了半天才读懂,它是要求输出满足条件的最小的矩阵面积。
    解决这类问题的重要办法就是降维,将二维降为一维。选取两列,将两列间元素相加,化为一维,再选取最小的大于k的最小连续长度
    第一版代码是这样:
  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define MAX 102
  6.  
  7. int matrix[MAX][MAX];
  8. int tr[MAX];
  9.  
  10. int main(int argc, char const *argv[])
  11. {
  12. int n, m, k;
  13. //freopen("input.txt","r",stdin);
  14. while(scanf("%d %d %d",&n, &m, &k) != EOF) {
  15. for(int i = ; i < n; i++) {
  16. for(int j = ; j < m; j++) {
  17. scanf("%d",&matrix[i][j]);
  18. }
  19. }
  20.  
  21. int ans = n*m + ;
  22. for(int i = ; i < m; i++) {
  23. for(int j = i; j < m; j++) {
  24. //from i to j
  25. memset(tr,,sizeof(tr));
  26. int ansij = -;
  27.  
  28. int base = j - i + ;
  29. for(int h = ; h < n; h++) {
  30. for(int q = i; q <= j; q++) {
  31. tr[h] = tr[h] + matrix[h][q];
  32. }
  33. }
  34. /*for(int h = 0; h < n; h++) {
  35. printf("%d ",tr[h]);
  36. }
  37. puts("");*/
  38. for(int len = ; len <= n; len++) {
  39. for(int u = ; u < n; u++) {
  40. int v = u + len -;
  41. if(v >= n) {
  42. break;
  43. }
  44. int sum = ;
  45. for(int w = u; w <= v; w++) {
  46. sum = sum + tr[w];
  47. }
  48. if(sum >= k) {
  49. ansij = len;
  50. break;
  51. }
  52. }
  53. if(ansij != -) {
  54. break;
  55. }
  56. }
  57. if(ansij != - && ansij *base < ans) {
  58. ans = ansij*base;
  59. }
  60. }
  61. }
  62. if(ans < n*m+) {
  63. printf("%d\n", ans);
  64. }
  65. else {
  66. puts("-1");
  67. }
  68.  
  69. }
  70. return ;
  71. }

时间为150ms

后来发现31行的累加很费时间,后来发现这个累加完全可以不用每回从头开始加,上一次的结果可以作为下一次的开始,代码修改为

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define MAX 102
  6.  
  7. int matrix[MAX][MAX];
  8. int tr[MAX];
  9.  
  10. int main(int argc, char const *argv[])
  11. {
  12. int n, m, k;
  13. //freopen("input.txt","r",stdin);
  14. while(scanf("%d %d %d",&n, &m, &k) != EOF) {
  15. for(int i = ; i < n; i++) {
  16. for(int j = ; j < m; j++) {
  17. scanf("%d",&matrix[i][j]);
  18. }
  19. }
  20.  
  21. int ans = n*m + ;
  22. for(int i = ; i < m; i++) {
  23. memset(tr,,sizeof(tr));
  24. for(int j = i; j < m; j++) {
  25. //from i to j
  26. int ansij = -;
  27.  
  28. int base = j - i + ;
  29. for(int h = ; h < n; h++) {
  30. tr[h] = tr[h] + matrix[h][j];
  31.  
  32. }
  33. /*for(int h = 0; h < n; h++) {
  34. printf("%d ",tr[h]);
  35. }
  36. puts("");*/
  37. for(int len = ; len <= n; len++) {
  38. for(int u = ; u < n; u++) {
  39. int v = u + len -;
  40. if(v >= n) {
  41. break;
  42. }
  43. int sum = ;
  44. for(int w = u; w <= v; w++) {
  45. sum = sum + tr[w];
  46. }
  47. if(sum >= k) {
  48. ansij = len;
  49. break;
  50. }
  51. }
  52. if(ansij != -) {
  53. break;
  54. }
  55. }
  56. if(ansij != - && ansij *base < ans) {
  57. ans = ansij*base;
  58. }
  59. }
  60. }
  61. if(ans < n*m+) {
  62. printf("%d\n", ans);
  63. }
  64. else {
  65. puts("-1");
  66. }
  67.  
  68. }
  69. return ;
  70. }

时间为120ms

发现在45行仍有累加,修改为如下:

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define MAX 102
  6.  
  7. int matrix[MAX][MAX];
  8. int tr[MAX];
  9. int dis[MAX][MAX];
  10.  
  11. int cal(int u, int v) {
  12. if(dis[u][v] != ) {
  13. return dis[u][v];
  14. }
  15. if(v == u) {
  16. dis[u][v] = tr[u];
  17. return dis[u][v];
  18. }
  19. else {
  20. dis[u][v] = dis[u][v-] + dis[v][v];
  21. return dis[u][v-] + dis[v][v];
  22. }
  23. }
  24.  
  25. int main(int argc, char const *argv[])
  26. {
  27. int n, m, k;
  28. //freopen("input.txt","r",stdin);
  29. while(scanf("%d %d %d",&n, &m, &k) != EOF) {
  30. for(int i = ; i < n; i++) {
  31. for(int j = ; j < m; j++) {
  32. scanf("%d",&matrix[i][j]);
  33. }
  34. }
  35.  
  36. int ans = n*m + ;
  37. for(int i = ; i < m; i++) {
  38. memset(tr,,sizeof(tr));
  39. for(int j = i; j < m; j++) {
  40. //from i to j
  41. int ansij = -;
  42.  
  43. int base = j - i + ;
  44. for(int h = ; h < n; h++) {
  45. tr[h] = tr[h] + matrix[h][j];
  46.  
  47. }
  48. /*for(int h = 0; h < n; h++) {
  49. printf("%d ",tr[h]);
  50. }
  51. puts("");*/
  52. memset(dis,,sizeof(dis));
  53.  
  54. for(int len = ; len <= n; len++) {
  55. for(int u = ; u < n; u++) {
  56. int v = u + len -;
  57. if(v >= n) {
  58. break;
  59. }
  60. int sum = cal(u,v);
  61. if(sum >= k) {
  62. ansij = len;
  63. break;
  64. }
  65. }
  66. if(ansij != -) {
  67. break;
  68. }
  69. }
  70. if(ansij != - && ansij *base < ans) {
  71. ans = ansij*base;
  72. }
  73. }
  74. }
  75. if(ans < n*m+) {
  76. printf("%d\n", ans);
  77. }
  78. else {
  79. puts("-1");
  80. }
  81.  
  82. }
  83. return ;
  84. }

时间为60ms

后来参考别人的代码,可以利用尺取法解决这个问题

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define MAX 102
  6.  
  7. int matrix[MAX][MAX];
  8. int tr[MAX];
  9.  
  10. int merge(int n, int goal) {
  11. int ans = -;
  12. int start = , end = , sum = ;
  13. while (end < n) {
  14. if (sum < goal)
  15. sum += tr[end];
  16. while (sum >= goal) {
  17. int len = end - start + ;
  18. if (ans == -) ans = len;
  19. else if (len < ans) ans = len;
  20. sum -= tr[start++];
  21. }
  22. ++end;
  23. }
  24. return ans;
  25. }
  26.  
  27. int main(int argc, char const *argv[])
  28. {
  29. int n, m, k;
  30. //freopen("input.txt","r",stdin);
  31. while(scanf("%d %d %d",&n, &m, &k) != EOF) {
  32. for(int i = ; i < n; i++) {
  33. for(int j = ; j < m; j++) {
  34. scanf("%d",&matrix[i][j]);
  35. }
  36. }
  37.  
  38. int ans = n*m + ;
  39. for(int i = ; i < m; i++) {
  40. memset(tr,,sizeof(tr));
  41. for(int j = i; j < m; j++) {
  42. //from i to j
  43. int ansij = -;
  44.  
  45. int base = j - i + ;
  46. for(int h = ; h < n; h++) {
  47. tr[h] = tr[h] + matrix[h][j];
  48.  
  49. }
  50. /*for(int h = 0; h < n; h++) {
  51. printf("%d ",tr[h]);
  52. }
  53. puts("");*/
  54. ansij = merge(n, k);
  55. if(ansij != - && ansij *base < ans) {
  56. ans = ansij*base;
  57. }
  58. }
  59. }
  60. if(ans < n*m+) {
  61. printf("%d\n", ans);
  62. }
  63. else {
  64. puts("-1");
  65. }
  66.  
  67. }
  68. return ;
  69. }

时间居然缩短到了10ms

九度oj 题目1102:最小面积子矩阵的更多相关文章

  1. 九度oj 题目1139:最大子矩阵

    题目描述: 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵. 比如,如下4 * 4的矩阵 0 -2 -7 0 9 2 -6 2 -4 1 ...

  2. 九度oj题目&amp;吉大考研11年机试题全解

    九度oj题目(吉大考研11年机试题全解) 吉大考研机试2011年题目: 题目一(jobdu1105:字符串的反码).    http://ac.jobdu.com/problem.php?pid=11 ...

  3. 九度oj 题目1007:奥运排序问题

    九度oj 题目1007:奥运排序问题   恢复 题目描述: 按要求,给国家进行排名. 输入:                        有多组数据. 第一行给出国家数N,要求排名的国家数M,国家号 ...

  4. 九度OJ 题目1384:二维数组中的查找

    /********************************* * 日期:2013-10-11 * 作者:SJF0115 * 题号: 九度OJ 题目1384:二维数组中的查找 * 来源:http ...

  5. hdu 1284 关于钱币兑换的一系列问题 九度oj 题目1408:吃豆机器人

    钱币兑换问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  6. 九度OJ 1502 最大值最小化(JAVA)

    题目1502:最大值最小化(二分答案) 九度OJ Java import java.util.Scanner; public class Main { public static int max(in ...

  7. 九度oj 题目1087:约数的个数

    题目链接:http://ac.jobdu.com/problem.php?pid=1087 题目描述: 输入n个整数,依次输出每个数的约数的个数 输入: 输入的第一行为N,即数组的个数(N<=1 ...

  8. 九度OJ题目1105:字符串的反码

    tips:scanf,cin输入字符串遇到空格就停止,所以想输入一行字符并保留最后的"\0"还是用gets()函数比较好,九度OJ真操蛋,true?没有这个关键字,还是用1吧,还是 ...

  9. 九度oj题目1009:二叉搜索树

    题目描述: 判断两序列是否为同一二叉搜索树序列 输入:                        开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接 ...

随机推荐

  1. JS语法学习笔记

    JS语法: JS知识点一览图 JS知识点一览图 在function中写this,在本function中可以显示,写Person则显示undefined. 在function中写Person,在func ...

  2. JavaScript30-7 数组的一些基本方法

    本次来学习数组的一些方法,之前学习的js数组的方法是在第四课里面(没有写到随笔里面) 之前第四课主要讲的是 filter() ,map() 这次课程主要介绍的是 some()`.`every()`.` ...

  3. css绝对定位元素实现居中的几个方法

    一:CSS绝对定位元素left设为50%实现水平居中 绝对定位的元素left设为50%时,是已左上角为原点的,所以只要再使用margin属性添加负值补偿回来即可.示例:[css]代码如下: #boar ...

  4. [Ubuntu]清除系统磁盘垃圾

    操作步骤: 1.sudo apt-get autoremove(卸载系统中所有未被使用的依赖关系) 2.sudo apt-get clean(清除所有缓存的包文件) 以上操作绿色无害,对系统无影响.

  5. 编写Robotium测试程序

    6.编写Robotium测试程序 1)导包 //导入需要测试的工程 import com.example.android.notepad.NotesList; //robotium提供的测试用类 im ...

  6. CodeForces 219D Choosing Capital for Treeland (树形DP)

    题意:给一个树形图,n个节点,n-1条有向边,要求选一个节点作为根,使需要改变方向的边的数目最少.并输出所有可能作为根的点. 思路: 先随便一个点进行DFS,计算将每棵子树的边全部往下时,所需要的费用 ...

  7. mysql ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2 "No such file or directory")

    解决方案如下:

  8. Netbeans使用笔记

    Netbeans 新建项目 A brand new project 选择"文件">"新建项目"以打开新建项目向导. 在向导中,选择 "C/C++ ...

  9. synchronized关键字修饰非静态方法与静态方法的区别

    这里我们先创建ObjLock类,并实现Runnable接口.并创建一个Demo类,具有被synchronized关键字修饰的非静态方法与静态方法. 非静态方法 public class ObjLock ...

  10. java在线聊天项目1.0版 异常处理——开启多个客户端,关闭一个客户端后,在其他客户端中再发出信息会出现异常的处理

    异常一 只开启一个客户端,输入信息后关闭,客户端出现如下异常 根据异常说明 ChatClientFrame客户端117行 提示原因是Socket关闭 分析原因 客户端代码 while (connect ...