ALGO-44 采油区域
资源限制
时间限制:2.0s 内存限制:512.0MB
问题描述
采油区域 Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油井。被拍卖的整块土地为一个矩形区域,被划分为M×N个小块。
Siruseri地质调查局有关于Navalur土地石油储量的估测数据。这些数据表示为M×N个非负整数,即对每一小块土地石油储量的估计值。
为了避免出现垄断,政府规定每一个承包商只能承包一个由K×K块相连的土地构成的正方形区域。AoE石油联合公司由三个承包商组成,他们想选择三块互不相交的K×K的区域使得总的收益最大。
例如,假设石油储量的估计值如下:
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 8 | 8 | 8 | 8 | 8 | 1 | 1 | 1 |
1 | 8 | 8 | 8 | 8 | 8 | 1 | 1 | 1 |
1 | 8 | 8 | 8 | 8 | 8 | 1 | 1 | 1 |
1 | 1 | 1 | 1 | 8 | 8 | 8 | 1 | 1 |
1 | 1 | 1 | 1 | 1 | 1 | 8 | 8 | 8 |
1 | 1 | 1 | 1 | 1 | 1 | 9 | 9 | 9 |
1 | 1 | 1 | 1 | 1 | 1 | 9 | 9 | 9 |
如果K = 2, AoE公司可以承包的区域的石油储量总和为100, 如果K = 3, AoE公司可以承包的区域的石油储量总和为208。
AoE公司雇佣你来写一个程序,帮助计算出他们可以承包的区域的石油储量之和的最大值。
输入格式
输入第一行包含三个整数M, N, K,其中M和N是矩形区域的行数和列数,K是每一个承包商承包的正方形的大小(边长的块数)。接下来M行,每行有N个非负整数表示这一行每一小块土地的石油储量的估计值。
输出格式
输出只包含一个整数,表示AoE公司可以承包的区域的石油储量之和的最大值。
测试样例
输入:
9 9 3
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 8 8 8 8 8 1 1 1
1 8 8 8 8 8 1 1 1
1 8 8 8 8 8 1 1 1
1 1 1 1 8 8 8 1 1
1 1 1 1 1 1 8 8 8
1 1 1 1 1 1 9 9 9
1 1 1 1 1 1 9 9 9
输出:
208
数据规模与约定
数据保证K≤M且K≤N并且至少有三个K×K的互不相交的正方形区域。其中30%的输入数据,M, N≤ 12。所有的输入数据, M, N≤ 1500。每一小块土地的石油储量的估计值是非负整数且≤ 500。
AC code:
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) {
InputReader in = new InputReader(System.in, " \n");
int m = in.nextInt(), n = in.nextInt(), k = in.nextInt(), k2 = k + k, res = 0;
int[][] map = new int[m + 1][n + 1],
TL = new int[m + 2][n + 2],
TR = new int[m + 2][n + 2],
BR = new int[m + 2][n + 2],
BL = new int[m + 2][n + 2];
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++) map[i][j] = map[i - 1][j] + map[i][j - 1] - map[i - 1][j - 1] + in.nextInt();
for (int i = m; i >= k; i--)
for (int j = n; j >= k; j--) map[i][j] -= map[i - k][j] + map[i][j - k] - map[i - k][j - k];
for (int i = k; i <= m; i++) for (int j = k; j <= n; j++) TL[i][j] = max(map[i][j], max(TL[i][j - 1], TL[i - 1][j]));
for (int i = k; i <= m; i++) for (int j = n; j >= k; j--) TR[i][j] = max(map[i][j], max(TR[i][j + 1], TR[i - 1][j]));
for (int i = m; i >= k; i--) for (int j = n; j >= k; j--) BR[i][j] = max(map[i][j], max(BR[i][j + 1], BR[i + 1][j]));
for (int i = m; i >= k; i--) for (int j = k; j <= n; j++) BL[i][j] = max(map[i][j], max(BL[i][j - 1], BL[i + 1][j]));
for (int i = k2; i <= m; i++)
for (int j = k2; j <= n; j++)
res = max(TL[i - k][j - k] + TR[i - k][j] + BL[i][n],
TL[i - k][j - k] + TR[m][j] + BL[i][j - k],
TL[i - k][n] + BL[i][j - k] + BR[i][j],
TL[m][j - k] + TR[i - k][j] + BR[i][j], res);
for (int j = k2, q = n - k, max = 0; j <= q; res = max(res, max + TL[m][j - k] + TR[m][j + k]), max = 0, j++)
for (int i = k, p = m - k; i <= p; i++) if (map[i][j] > max) max = map[i][j];
for (int i = k2, l = m - k, max = 0; i <= l; res = max(res, max + TL[i - k][n] + BL[i + k][n]), max = 0, i++)
for (int j = k; j <= n; j++) if (map[i][j] > max) max = map[i][j];
System.out.print(res);
}
static int max(int var1, int var2) { return var1 > var2? var1: var2; };
static int max(int var1, int var2, int var3, int var4, int var5) { return max(var1, max(var2, max(var3, max(var4, var5)))); };
static class InputReader {
BufferedReader read;
StringTokenizer token;
String delimiters;
InputReader(InputStream in) { this(in, " \t\n\r\f"); }
InputReader(InputStream in, String delimiters) {
this.read = new BufferedReader(new InputStreamReader(in));
this.token = new StringTokenizer("", this.delimiters = delimiters);
}
String next() {
while (!token.hasMoreTokens())
try {
this.token = new StringTokenizer(read.readLine(), delimiters);
} catch (IOException e) {
e.printStackTrace();
}
return token.nextToken();
}
int nextInt() { return Integer.parseInt(next()); }
}
}
思路参考
图一画,这题就很明了了
递推出拆分部分在 左上、右上、右下、左下 的最大值
再进行枚举
最后特殊处理一下 #5、#6 这两个用例
调试了半天,比赛要是出这种题,我怎么来的怎么回去
用例10: 8.11 MB,我本以为Java必不过,精了
before
没头绪,先整手暴搜:
import java.io.*;
import java.util.*;
public class Main {
static int map[][], x1, y1, x2, y2, K, M, N, max;
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
M = in.nextInt(); N = in.nextInt(); K = in.nextInt();
map = new int[M + 1][N + 1];
for (int i = 1; i <= M; i++)
for (int j = 1; j <= N; j++) map[i][j] = map[i][j - 1] + map[i - 1][j] - map[i - 1][j - 1] + in.nextInt();
for (int i = M; i >= K; i--)
for (int j = N; j >= K; j--) map[i][j] -= map[i][j - K] + map[i - K][j] - map[i - K][j - K];
full(0);
System.out.print(max);
}
static void full(int step) {
for (int i = K; i <= M; i++)
for (int j = K; j <= N; j++) {
if (noPut(i, j)) continue;
switch (step) {
case 0: x1 = i; y1 = j; full(1); x1 = 0; break;
case 1: x2 = i; y2 = j; full(2); x2 = 0; break;
default: max = max(max, map[x1][y1] + map[x2][y2] + map[i][j]);
}
}
}
static boolean noPut(int x, int y) {
if (x1 > 0 && abs(x1 - x) < K && abs(y1 - y) < K) return true;
if (x2 > 0 && abs(x2 - x) < K && abs(y2 - y) < K) return true;
return false;
}
public static int abs(int var) { return var < 0? -var: var; }
public static int max(int var1, int var2) { return var1 > var2? var1: var2; }
static class InputReader {
BufferedReader read;
StringTokenizer token;
String delimiters;
InputReader(InputStream in) { this(in, " \t\n\r\f"); }
InputReader(InputStream in, String delimiters) {
this.read = new BufferedReader(new InputStreamReader(in));
this.token = new StringTokenizer("", this.delimiters = delimiters);
}
String next() {
while (!token.hasMoreTokens())
try {
this.token = new StringTokenizer(read.readLine(), delimiters);
} catch (IOException e) {
e.printStackTrace();
}
return token.nextToken();
}
int nextInt() { return Integer.parseInt(next()); }
}
}
30分,已经很可以了
朋友叫我出去玩了,回家再做研究