题目描述:

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

输入:

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

输出:

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

样例输入:
4 4 10
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
样例输出:
1

这道题的题意读了半天才读懂,它是要求输出满足条件的最小的矩阵面积。
解决这类问题的重要办法就是降维,将二维降为一维。选取两列,将两列间元素相加,化为一维,再选取最小的大于k的最小连续长度
第一版代码是这样:
 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define MAX 102 int matrix[MAX][MAX];
int tr[MAX]; int main(int argc, char const *argv[])
{
int n, m, k;
//freopen("input.txt","r",stdin);
while(scanf("%d %d %d",&n, &m, &k) != EOF) {
for(int i = ; i < n; i++) {
for(int j = ; j < m; j++) {
scanf("%d",&matrix[i][j]);
}
} int ans = n*m + ;
for(int i = ; i < m; i++) {
for(int j = i; j < m; j++) {
//from i to j
memset(tr,,sizeof(tr));
int ansij = -; int base = j - i + ;
for(int h = ; h < n; h++) {
for(int q = i; q <= j; q++) {
tr[h] = tr[h] + matrix[h][q];
}
}
/*for(int h = 0; h < n; h++) {
printf("%d ",tr[h]);
}
puts("");*/
for(int len = ; len <= n; len++) {
for(int u = ; u < n; u++) {
int v = u + len -;
if(v >= n) {
break;
}
int sum = ;
for(int w = u; w <= v; w++) {
sum = sum + tr[w];
}
if(sum >= k) {
ansij = len;
break;
}
}
if(ansij != -) {
break;
}
}
if(ansij != - && ansij *base < ans) {
ans = ansij*base;
}
}
}
if(ans < n*m+) {
printf("%d\n", ans);
}
else {
puts("-1");
} }
return ;
}

时间为150ms

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

 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define MAX 102 int matrix[MAX][MAX];
int tr[MAX]; int main(int argc, char const *argv[])
{
int n, m, k;
//freopen("input.txt","r",stdin);
while(scanf("%d %d %d",&n, &m, &k) != EOF) {
for(int i = ; i < n; i++) {
for(int j = ; j < m; j++) {
scanf("%d",&matrix[i][j]);
}
} int ans = n*m + ;
for(int i = ; i < m; i++) {
memset(tr,,sizeof(tr));
for(int j = i; j < m; j++) {
//from i to j
int ansij = -; int base = j - i + ;
for(int h = ; h < n; h++) {
tr[h] = tr[h] + matrix[h][j]; }
/*for(int h = 0; h < n; h++) {
printf("%d ",tr[h]);
}
puts("");*/
for(int len = ; len <= n; len++) {
for(int u = ; u < n; u++) {
int v = u + len -;
if(v >= n) {
break;
}
int sum = ;
for(int w = u; w <= v; w++) {
sum = sum + tr[w];
}
if(sum >= k) {
ansij = len;
break;
}
}
if(ansij != -) {
break;
}
}
if(ansij != - && ansij *base < ans) {
ans = ansij*base;
}
}
}
if(ans < n*m+) {
printf("%d\n", ans);
}
else {
puts("-1");
} }
return ;
}

时间为120ms

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

 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define MAX 102 int matrix[MAX][MAX];
int tr[MAX];
int dis[MAX][MAX]; int cal(int u, int v) {
if(dis[u][v] != ) {
return dis[u][v];
}
if(v == u) {
dis[u][v] = tr[u];
return dis[u][v];
}
else {
dis[u][v] = dis[u][v-] + dis[v][v];
return dis[u][v-] + dis[v][v];
}
} int main(int argc, char const *argv[])
{
int n, m, k;
//freopen("input.txt","r",stdin);
while(scanf("%d %d %d",&n, &m, &k) != EOF) {
for(int i = ; i < n; i++) {
for(int j = ; j < m; j++) {
scanf("%d",&matrix[i][j]);
}
} int ans = n*m + ;
for(int i = ; i < m; i++) {
memset(tr,,sizeof(tr));
for(int j = i; j < m; j++) {
//from i to j
int ansij = -; int base = j - i + ;
for(int h = ; h < n; h++) {
tr[h] = tr[h] + matrix[h][j]; }
/*for(int h = 0; h < n; h++) {
printf("%d ",tr[h]);
}
puts("");*/
memset(dis,,sizeof(dis)); for(int len = ; len <= n; len++) {
for(int u = ; u < n; u++) {
int v = u + len -;
if(v >= n) {
break;
}
int sum = cal(u,v);
if(sum >= k) {
ansij = len;
break;
}
}
if(ansij != -) {
break;
}
}
if(ansij != - && ansij *base < ans) {
ans = ansij*base;
}
}
}
if(ans < n*m+) {
printf("%d\n", ans);
}
else {
puts("-1");
} }
return ;
}

时间为60ms

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

 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define MAX 102 int matrix[MAX][MAX];
int tr[MAX]; int merge(int n, int goal) {
int ans = -;
int start = , end = , sum = ;
while (end < n) {
if (sum < goal)
sum += tr[end];
while (sum >= goal) {
int len = end - start + ;
if (ans == -) ans = len;
else if (len < ans) ans = len;
sum -= tr[start++];
}
++end;
}
return ans;
} int main(int argc, char const *argv[])
{
int n, m, k;
//freopen("input.txt","r",stdin);
while(scanf("%d %d %d",&n, &m, &k) != EOF) {
for(int i = ; i < n; i++) {
for(int j = ; j < m; j++) {
scanf("%d",&matrix[i][j]);
}
} int ans = n*m + ;
for(int i = ; i < m; i++) {
memset(tr,,sizeof(tr));
for(int j = i; j < m; j++) {
//from i to j
int ansij = -; int base = j - i + ;
for(int h = ; h < n; h++) {
tr[h] = tr[h] + matrix[h][j]; }
/*for(int h = 0; h < n; h++) {
printf("%d ",tr[h]);
}
puts("");*/
ansij = merge(n, k);
if(ansij != - && ansij *base < ans) {
ans = ansij*base;
}
}
}
if(ans < n*m+) {
printf("%d\n", ans);
}
else {
puts("-1");
} }
return ;
}

时间居然缩短到了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. phpMyAdmin 缺少 mcrypt 扩展.请检查 PHP 配置.

    原文链接:http://zhidao.baidu.com/link?url=5Y4eT7bcnTHFUtzDMs7mvtsGc7jqbs2yqXG06AP5_6t7wukC7uVozSrbUf7iYl ...

  2. Windows 10下mysql 64位 安装(mysql-5.7.11-winx64安装)

    Windows下mysql 64位 安装(mysql-5.7.11-winx64安装) 系统Windows10 安装包mysql-5.7.11-winx64.zip 安装过程中遇到的问题,请留意4.0 ...

  3. 自定义消息中如果需要定义WPARAM和LPARAM,该怎么使用和分配?

    写Windows程序不可避免要使用自定义的消息,也就是从WM_USER开始定义的消息.在定义一个消息后,往往我们还要定义针对该消息的WPARAM甚至是LPARAM.WPARAM和LPARAM是什么,可 ...

  4. c语言中的赋值

    int s,i,len,err=0 这个是只给err赋了值还是这四个都有?

  5. Oracle Flashback Technology【闪回技术】

    -------------------------与其他数据库相比,Oracle的闪回让开发者多了一条选择的路. Flashback的目的 先看下Oracle官方文档中的解释: Oracle Flas ...

  6. IOS画线条

    - (void)drawRect:(CGRect)rect { // draw a rounded rect bezier path filled with blue CGContextRef aRe ...

  7. Drools应用实例

    Drools 实例介绍 Drools编译与运行: 在Drools当中,规则的编译与运行要通过Drools提供的各种API来实现,这些API总体来讲可以分为三类:规则编译.规则收集和规则的执行. Kmo ...

  8. Windows64+Python27下配置matplotlib

    注:转载请注明原作者并附上原文链接! 网上看了很多方法,均遇到这样或者那样的问题导致安装失败,最后自己摸索一条方法,最终安装成功了. 1,首先安装numpy,这个可以选择install安装包,很简单, ...

  9. codevs 1145 Hanoi双塔问题 2007年NOIP全国联赛普及组

    时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 给定A.B.C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的 ...

  10. 签名ipa,让其它手机也安装

    开发的时候,需要将app让其它人装上测试,虽然通过xcode可以使用编译进去,但是仍显不方便. 网上有个工具, http://code.google.com/p/iresign/ 通过这个工具,使用自 ...