APIO-采油区域解题思路与参考代码

本文介绍了一种求解二维矩阵中最大子矩阵和的方法。首先预处理得到矩阵的前缀和,接着通过四步计算出以每个位置为顶点的最大k*k子矩阵和。最后通过六种情况讨论,得出最终答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

View Code
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 
  6 #define gmax(a,b) ((a)>(b)?(a):(b))
  7 #define fill(a,b) memset(a,b,sizeof(a))
  8 #define MAXN 2000
  9 #define MAXM 2000
 10 
 11 using namespace std;
 12 
 13 int n, m, k;
 14 int a[MAXN][MAXM];
 15 int s[MAXN][MAXM];
 16 int ak[MAXN][MAXM];
 17 int lu[MAXN][MAXM], ru[MAXN][MAXM], ld[MAXN][MAXM], rd[MAXN][MAXM];
 18 int ans;
 19 
 20 int main(){
 21     
 22     freopen("oil.in", "r", stdin);
 23     freopen("oil.out", "w", stdout);
 24     
 25     int i, j;
 26     scanf("%d %d %d", &n, &m, &k);
 27     for (i=1; i<n+1; i++){
 28         for (j=1; j<m+1; j++){
 29             scanf("%d", &a[i][j]);
 30             }
 31         }
 32     //
 33     fill(s, 0);
 34     for (i=1; i<n+1; i++){
 35         for (j=1; j<m+1; j++){
 36             s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
 37             }
 38         }
 39     //
 40     fill(ak, 0);
 41     for (i=k; i<n+1; i++){
 42         for (j=k; j<m+1; j++){
 43             ak[i][j] = s[i][j] - s[i - k][j] - s[i][j - k] + s[i - k][j - k];
 44             }
 45         }
 46     //
 47     fill(lu, 0);
 48     for (i=k; i<n+1; i++){
 49         for (j=k; j<m+1; j++){
 50             lu[i][j] = ak[i][j];
 51             lu[i][j] = gmax(lu[i][j], lu[i - 1][j]);
 52             lu[i][j] = gmax(lu[i][j], lu[i][j - 1]);
 53             }
 54         }
 55     //
 56     fill(ru, 0);
 57     for (i=k; i<n+1; i++){
 58         for (j=m-k+1; j; j--){
 59             ru[i][j] = ak[i][j + k - 1];
 60             ru[i][j] = gmax(ru[i][j], ru[i - 1][j]);
 61             ru[i][j] = gmax(ru[i][j], ru[i][j + 1]);
 62             }
 63         }
 64     //
 65     fill(ld, 0);
 66     for (i=n-k+1; i; i--){
 67         for (j=k; j<m+1; j++){
 68             ld[i][j] = ak[i + k - 1][j];
 69             ld[i][j] = gmax(ld[i][j], ld[i + 1][j]);
 70             ld[i][j] = gmax(ld[i][j], ld[i][j - 1]);
 71             }
 72         }
 73     //
 74     fill(rd, 0);
 75     for (i=n-k+1; i; i--){
 76         for (j=m-k+1; j; j--){
 77             rd[i][j] = ak[i + k - 1][j + k - 1];
 78             rd[i][j] = gmax(rd[i][j], rd[i + 1][j]);
 79             rd[i][j] = gmax(rd[i][j], rd[i][j + 1]);
 80             }
 81         }
 82     //
 83     ans = 0;
 84     //
 85     //1|1|1
 86     //
 87     for (j=k; j+(k<<1)<m+1; j++){
 88         for (i=k; i<n+1; i++){
 89             int t = lu[n][j] + ak[i][j + k] + ru[n][j + k + 1];
 90             ans = gmax(ans, t);
 91             }
 92         }
 93     //
 94     //1
 95     //1
 96     //1
 97     for (i=k; i+(k<<1)<n+1; i++){
 98         for (j=k; j<m+1; j++){
 99             int t = lu[i][m] + ak[i + k][j] + ld[i + k + 1][m];
100             ans = gmax(ans, t);
101             }
102         }
103     //
104     // 1
105     //1|
106     // 1
107     for (j=k; j+k<m+1; j++){
108         for (i=k; i+k<n+1; i++){
109             int t = lu[n][j] + ru[i][j + 1] + rd[i + 1][j + 1];
110             ans = gmax(ans, t);
111             }
112         }
113     //
114     //1
115     // |1
116     //1
117     for (j=k; j+k<m+1; j++){
118         for (i=k; i+k<n+1; i++){
119             int t = lu[i][j] + ld[i + 1][j] + rd[1][j + 1];
120             ans = gmax(ans, t);
121             }
122         }
123     //
124     // 1
125     //1 1
126     for (i=k; i+k<n+1; i++){
127         for (j=k; j+k<m+1; j++){
128             int t = lu[i][n] + ld[i + 1][j] + rd[i + 1][j + 1];
129             ans = gmax(ans, t);
130             }
131         }
132     //
133     //1 1
134     // 1
135     for (i=k; i+k<n+1; i++){
136         for (j=k; j+k<m+1; j++){
137             int t = lu[i][j] + ru[i][j + 1] + ld[i + 1][m];
138             ans = gmax(ans, t);
139             }
140         }
141     
142     
143     printf("%d\n", ans);
144     
145     fclose(stdin);
146     fclose(stdout);
147     
148     return 0;
149     

主要思想就是,

肯定要预处理出来矩阵前缀和

s[i][j]代表1..i行1..j列数字之和。

然后处理出以(i,j)为右下角的k*k的矩阵元素之和。

然后分别处理出以(i,j)为左上角,左下角,右上角,右下角的最大矩阵中最大的k*k的值。

然后分6中情况讨论(每种情况都是2层循环,所以总复杂度是O(n^2)的)

今天评测时发现速度不太快,好几个1s多,但是对于官方要求的1.5s还是AC了。

转载于:https://www.cnblogs.com/alanlau2011/archive/2012/07/15/2592522.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值