九度OJ 1102:最小面积子矩阵 (DP、缓存、剪枝)
2015-10-23 17:01
441 查看
时间限制:1 秒
内存限制:32 兆
特殊判题:否
提交:1666
解决:504
题目描述:
一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵(矩阵中元素个数为矩阵面积)
输入:
每个案例第一行三个正整数N,M<=100,表示矩阵大小,和一个整数K
接下来N行,每行M个数,表示矩阵每个元素的值
输出:
输出最小面积的值。如果出现任意矩阵的和都小于K,直接输出-1。
样例输入:
样例输出:
来源:2010年上海交通大学计算机研究生机试真题
思路:
暴力求解必然超时。此题在计算过程中有大量重复计算数据,应该进行缓存,有效利用,我的思路是b[i][j]保存第j列前i行的数之和,计算子矩阵和的时候,调用前一个sum与相应的b中元素计算。另外对于area大于当前搜索到的最小area的情况,不需要再搜索。
利用这些缓存和剪枝,我的代码运行时间从一开始的超时到最后的30ms。
其他人最好的运行时间是10ms,我没有再深入研究。我的代码应该仍有一定的优化余地。
代码:
代码2:
另一个人的10ms代码,我看了一下,跟我的代码总体思路不一样,但是利用的缓存粒度相同,而且他没有对面积剪枝,为什么时间这么短呢?
内存限制:32 兆
特殊判题:否
提交:1666
解决:504
题目描述:
一个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
来源:2010年上海交通大学计算机研究生机试真题
思路:
暴力求解必然超时。此题在计算过程中有大量重复计算数据,应该进行缓存,有效利用,我的思路是b[i][j]保存第j列前i行的数之和,计算子矩阵和的时候,调用前一个sum与相应的b中元素计算。另外对于area大于当前搜索到的最小area的情况,不需要再搜索。
利用这些缓存和剪枝,我的代码运行时间从一开始的超时到最后的30ms。
运行编号 | 用户 | 问题 | 结果 | 详情 | 内存 | 代码长度 | 耗时 | 语言 | 提交时间 |
---|---|---|---|---|---|---|---|---|---|
1368679 | liangrx06 | 1102 | Accepted | 1028KB | 1397B | 30MS | C++ / 代码 / 编辑 | 17:16:12 | |
1360553 | liangrx06 | 1102 | Accepted | 912KB | 1170B | 140MS | C / 代码 / 编辑 | 17:16:27 | |
1360547 | liangrx06 | 1102 | Accepted | 952KB | 1094B | 730MS | C / 代码 / 编辑 | 17:02:51 | |
1360543 | liangrx06 | 1102 | Wrong Answer | 952KB | 1042B | 740MS | C / 代码 / 编辑 | 16:59:39 | |
1360542 | liangrx06 | 1102 | Wrong Answer | 952KB | 1044B | 800MS | C / 代码 / 编辑 | 16:58:00 | |
1360535 | liangrx06 | 1102 | Memory Limit Exceed | 391428KB | 1230B | 0MS | C / 代码 / 编辑 | 16:48:23 | |
1360529 | liangrx06 | 1102 | Time Limit Exceed | 912KB | 1198B | >1000MS | C / 代码 / 编辑 | 16:36:53 |
代码:
#include <stdio.h> #define N 100 int main(void) { int n, m, k; int a , b ; int i, j, ii, jj; int min, sum, area; while (scanf("%d%d%d", &n, &m, &k) != EOF) { for(i=0; i<n; i++) { for (j=0; j<m; j++) { scanf("%d", &a[i][j]); if (i == 0) b[i][j] = a[i][j]; else b[i][j] = b[i-1][j] + a[i][j]; } } min = N*N+1; for(i=0; i<n; i++) { for (j=0; j<m; j++) { for (ii=i; ii<n; ii++) { sum = 0; for (jj=j; jj<m; jj++) { area = (ii-i+1)*(jj-j+1); if (area >= min) break; sum += b[ii][jj]; if (i > 0) sum -= b[i-1][jj]; if (sum >= k) min = area; } } } } if (min == N*N+1) min = -1; printf("%d\n", min); } return 0; } /************************************************************** Problem: 1102 User: liangrx06 Language: C Result: Accepted Time:30 ms Memory:916 kb ****************************************************************/
代码2:
另一个人的10ms代码,我看了一下,跟我的代码总体思路不一样,但是利用的缓存粒度相同,而且他没有对面积剪枝,为什么时间这么短呢?
#include<stdio.h> #include<algorithm> #include<string.h> #include<stack> #include<ctype.h> #include<numeric> using namespace std; stack<int>stk; int mat[110][110]; int h[110]; int calc(int n,int lim) { int ret=n+1,tmp; int f=0,r=0,sum=0; for(r=0;r<n;r++) { sum+=h[r]; while(sum>=lim) { tmp=r-f+1; if(tmp<ret)ret=tmp; sum-=h[f]; f++; } } if(ret==n+1)return -1; return ret; } int main() { int n,m,i,j; int k; while(scanf("%d%d%d",&n,&m,&k)!=EOF) { for(i=0;i<n;i++) { for(j=0;j<m;j++) { scanf("%d",&mat[i][j]); } } if(k<=0) { puts("0"); continue; } int ans=-1; for(i=0;i<n;i++) { memset(h,0,sizeof(h)); for(j=i;j<n;j++) { for(int t=0;t<m;t++) { h[t]+=mat[j][t]; } int tmp=calc(m,k)*(j-i+1); if(tmp<0)continue; if(ans==-1||tmp<ans)ans=tmp; } } printf("%d\n",ans); } return 0; } /************************************************************** Problem: 1102 User: 鬼M Language: C++ Result: Accepted Time:10 ms Memory:1072 kb ****************************************************************/
相关文章推荐
- 在Windows服务器上启用TLS 1.2及TLS 1.2基本原理
- 学习英语
- 常用端口号
- adb 用法
- 软件工程与计算机科学的区别
- jquery动态改变div宽度和高度
- ORACLE日期时间函数大全
- 在Linux中让echo命令显示带颜色的字
- 求数组中未出现的最小正整数
- 112家IT公司薪水一览表
- 九度OJ 1101:计算表达式 (DP)
- 【栈】bzoj 1007 水平可见直线
- Icocoapods 官方第三方库管理
- 第七章、供应市场调研
- 九度OJ 1101:计算表达式 (DP)
- NodeJS 实现基于 token 的认证应用
- C语言中“指针”作为“函数参数”时的注意事项
- ubuntu下安装vim失败,不满足依赖关系
- FreeBSD中配置FTP
- HTTP1.1中CHUNKED编码解析