九度oj 题目1102:最小面积子矩阵

题目描述:

一个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的最小连续长度第一版代码是这样:
 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 = 0; i < n; i++) {
16         for(int j = 0; j < m; j++) {
17             scanf("%d",&matrix[i][j]);
18         }
19        }
20
21        int ans = n*m + 1;
22        for(int i = 0; i < m; i++) {
23             for(int j = i; j < m; j++) {
24                 //from i to j
25                 memset(tr,0,sizeof(tr));
26                 int ansij = -1;
27
28                 int base = j - i + 1;
29                 for(int h = 0; 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 = 1; len <= n; len++) {
39                     for(int u = 0; u < n; u++) {
40                         int v = u + len -1;
41                         if(v >= n) {
42                             break;
43                         }
44                         int sum = 0;
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 != -1) {
54                         break;
55                     }
56                 }
57                 if(ansij != -1 && ansij *base < ans) {
58                     ans = ansij*base;
59                 }
60             }
61        }
62        if(ans < n*m+1) {
63             printf("%d\n", ans);
64        }
65        else {
66             puts("-1");
67        }
68
69     }
70     return 0;
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 = 0; i < n; i++) {
16         for(int j = 0; j < m; j++) {
17             scanf("%d",&matrix[i][j]);
18         }
19        }
20
21        int ans = n*m + 1;
22        for(int i = 0; i < m; i++) {
23             memset(tr,0,sizeof(tr));
24             for(int j = i; j < m; j++) {
25                 //from i to j
26                 int ansij = -1;
27
28                 int base = j - i + 1;
29                 for(int h = 0; 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 = 1; len <= n; len++) {
38                     for(int u = 0; u < n; u++) {
39                         int v = u + len -1;
40                         if(v >= n) {
41                             break;
42                         }
43                         int sum = 0;
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 != -1) {
53                         break;
54                     }
55                 }
56                 if(ansij != -1 && ansij *base < ans) {
57                     ans = ansij*base;
58                 }
59             }
60        }
61        if(ans < n*m+1) {
62             printf("%d\n", ans);
63        }
64        else {
65             puts("-1");
66        }
67
68     }
69     return 0;
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] != 0) {
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-1] + dis[v][v];
21         return dis[u][v-1] + 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 = 0; i < n; i++) {
31         for(int j = 0; j < m; j++) {
32             scanf("%d",&matrix[i][j]);
33         }
34        }
35
36        int ans = n*m + 1;
37        for(int i = 0; i < m; i++) {
38             memset(tr,0,sizeof(tr));
39             for(int j = i; j < m; j++) {
40                 //from i to j
41                 int ansij = -1;
42
43                 int base = j - i + 1;
44                 for(int h = 0; 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,0,sizeof(dis));
53
54                 for(int len = 1; len <= n; len++) {
55                     for(int u = 0; u < n; u++) {
56                         int v = u + len -1;
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 != -1) {
67                         break;
68                     }
69                 }
70                 if(ansij != -1 && ansij *base < ans) {
71                     ans = ansij*base;
72                 }
73             }
74        }
75        if(ans < n*m+1) {
76             printf("%d\n", ans);
77        }
78        else {
79             puts("-1");
80        }
81
82     }
83     return 0;
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 = -1;
12     int start = 0, end = 0, sum = 0;
13     while (end < n) {
14         if (sum < goal)
15             sum += tr[end];
16         while (sum >= goal) {
17             int len = end - start + 1;
18             if (ans == -1) 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 = 0; i < n; i++) {
33         for(int j = 0; j < m; j++) {
34             scanf("%d",&matrix[i][j]);
35         }
36        }
37
38        int ans = n*m + 1;
39        for(int i = 0; i < m; i++) {
40             memset(tr,0,sizeof(tr));
41             for(int j = i; j < m; j++) {
42                 //from i to j
43                 int ansij = -1;
44
45                 int base = j - i + 1;
46                 for(int h = 0; 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 != -1 && ansij *base < ans) {
56                     ans = ansij*base;
57                 }
58             }
59        }
60        if(ans < n*m+1) {
61             printf("%d\n", ans);
62        }
63        else {
64             puts("-1");
65        }
66
67     }
68     return 0;
69 }

时间居然缩短到了10ms

时间: 2024-10-08 20:50:45

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

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

题目描述: 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵. 比如,如下4 * 4的矩阵 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 的最大子矩阵是 9 2 -4 1 -1 8 这个子矩阵的大小是15. 输入: 输入是一个N * N的矩阵.输入的第一行给出N (0 < N <= 100). 再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2

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

九度oj 题目1007:奥运排序问题   恢复 题目描述: 按要求,给国家进行排名. 输入:                        有多组数据. 第一行给出国家数N,要求排名的国家数M,国家号从0到N-1. 第二行开始的N行给定国家或地区的奥运金牌数,奖牌数,人口数(百万). 接下来一行给出M个国家号. 输出:                        排序有4种方式: 金牌总数 奖牌总数 金牌人口比例 奖牌人口比例 对每个国家给出最佳排名排名方式 和 最终排名 格式为: 排名:排名

九度oj 题目1546:迷宫问题 (概率dp guess消元)

题目链接:点击打开链接 题目描述: 给定一个n*m的迷宫,如 S.. ..# E.E 其中,S代表开始位置,#代表不可行走的墙,E代表出口. 主人公从开始位置出发,每次等概率的随机选择下一个可以行走的位置,直到到达某一个出口为止. 现在他想知道,在这一概率事件中,它从开始位置走到某一个出口的期望步数是多少. 输入: 输入包含多组测试用例,每组测试用例由两个整数n,m(1<=n,m<=15)开始,代表迷宫的大小 接下去n行每行m个字符描述迷宫信息,具体规则如题面所述. 数据保证至少存在一个E和一

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

题目描述: 判断两序列是否为同一二叉搜索树序列 输入:                        开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树. 接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树. 输出:                        如果序列相同则输出YES,否则输出NO 样

九度OJ—题目1020:最小长方形

题目描述:     给定一系列2维平面点的坐标(x, y),其中x和y均为整数,要求用一个最小的长方形框将所有点框在内.长方形框的边分别平行于x和y坐标轴,点落在边上也算是被框在内. 输入: 测试输入包含若干测试用例,每个测试用例由一系列坐标组成,每对坐标占一行,其中|x|和|y|小于 231:一对0 坐标标志着一个测试用例的结束.注意(0, 0)不作为任何一个测试用例里面的点.一个没有点的测试用例标志着整个输入的结束. 输出: 对每个测试用例,在1行内输出2对整数,其间用一个空格隔开.第1对整

九度oj 题目1452:搬寝室

题目描述: 搬寝室是很累的,xhd深有体会.时间追述2006年7月9号,那天xhd迫于无奈要从27号楼搬到3号楼,因为10号要封楼了.看着寝室里的n件物品,xhd开始发呆,因为n是一个小于2000的整数,实在是太多了,于是xhd决定随便搬2*k件过去就行了.但还是会很累,因为2*k也不小是一个不大于n的整数.幸运的是xhd根据多年的搬东西的经验发现每搬一次的疲劳度是和左右手的物品的重量差的平方成正比(这里补充一句,xhd每次搬两件东西,左手一件右手一件).例如xhd左手拿重量为3的物品,右手拿重

九度oj 题目1171:C翻转

题目描述: 首先输入一个5 * 5的数组,然后输入一行,这一行有四个数,前两个代表操作类型,后两个数x y代表需操作数据为以x y为左上角的那几个数据. 操作类型有四种:  1 2 表示:90度,顺时针,翻转4个数  1 3 表示:90度,顺时针,翻转9个数  2 2 表示:90度,逆时针,翻转4个数  2 3 表示:90度,逆时针,翻转9个数 输入: 输入有多组数据. 每组输入一个5 * 5的数组,然后输入一行,这一行有四个数,前两个代表操作类型,后两个数x y代表需操作数据为以x y为左上角

九度oj 题目1034:寻找大富翁

题目链接:http://ac.jobdu.com/problem.php?pid=1034 题目描述:     浙江桐乡乌镇共有n个人,请找出该镇上的前m个大富翁. 输入:     输入包含多组测试用例.    每个用例首先包含2个整数n(0<n<=100000)和m(0<m<=10),其中: n为镇上的人数,m为需要找出的大富翁数, 接下来一行输入镇上n个人的财富值.    n和m同时为0时表示输入结束. 输出:     请输出乌镇前m个大富翁的财产数,财产多的排前面,如果大富翁

九度oj 题目1347:孤岛连通工程

题目描述: 现在有孤岛n个,孤岛从1开始标序一直到n,有道路m条(道路是双向的,如果有多条道路连通岛屿i,j则选择最短的那条),请你求出能够让所有孤岛都连通的最小道路总长度. 输入: 数据有多组输入. 每组第一行输入n(1<=n<=1000),m(0<=m<=10000). 接着m行,每行输入一条道路i j d(0<=d<=1000),(i,j表示岛屿序号,d表示道路长度). 输出: 对每组输入输出一行,如果能连通,输出能连通所有岛屿的最小道路长度,否则请输出字符串&q