您的位置:首页 > 编程语言

网易2017校园招聘数据挖掘笔试题编程题 分田地

2016-08-04 10:15 609 查看

题目:

牛牛和15个朋友玩打土豪分田地的游戏,牛牛决定让你来分田地,地主的田地可以看成是一个矩形,每个位置有一个价值。分割田地的方法是横竖各切三刀,分成16份,作为领导干部,牛牛总是会选择其中总价值最小的一份田地,作为牛牛最好的朋友,你希望牛牛取得的田地的价值和尽可能大,你知道这个值最大可以是多少吗?

输入描述

每个输入包含1个测试用例。每个测试用例的第一行包含两个整数n和m(1 <= n,m <= 75),表示田地的大小,接下来的n行,每行包含m个0-9之间的数字,表示每块位置的价值。

输出描述

输出一行表示牛牛所能取得的最大的价值。

输入例子

4 4

3332

3233

3332

2323

输出例子

2

思路

“最小值最大问题”,先二分试试。

枚举横向的三刀,纵向上在二分答案后贪心地靠左切,使得每个区域刚好全部大于等于答案,根据能否切满三刀来确定答案区间。这个时间复杂度算一下是O(n3mlogx)的,其中x是最大可能答案。

对于题目中给的数据,这样的复杂度表示鸭梨山大(codeforces.com除外),得考虑一下如何优化。

依然枚举横向的三刀,现在问题是如何确定这三刀,使得16个区域最小值最大。不妨先切中间那刀,那么问题变为如何切左边那刀和右边那刀,很显然这两个问题相互独立。用f[i]表示前i列的最优切法所得到的值,g[i]表示i~m列的最优切法得到的值,那么答案=max(min(f[i],g[i+1])),1<=i<m。容易证明f[i]和g[i]的最优决策都是单调的,于是它们都可以在O(m)的时间内算出来,因此最后复杂度变为O(n3m)。

参考程序一(枚举+二分):

#include <bits/stdc++.h>
using namespace std;
int n, m, a[100][100], sum[100][100], l, r, M;

int getsum(int x1, int y1, int x2, int y2) {
return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
}
bool ok(int val, int ix, int jx, int kx, int y1, int y2) {
int v1 = getsum(1, y1, ix, y2);
int v2 = getsum(ix + 1, y1, jx, y2);
int v3 = getsum(jx + 1, y1, kx, y2);
int v4 = getsum(kx + 1, y1, n, y2);
return v1 >= val && v2 >= val && v3 >= val && v4 >= val;
}
bool chk(int x) {
int c, y1;
for (int i = 1; i < n; i++) {
for (int j = i + 1; j < n; j++) {
for (int k = j + 1; k < n; k++) {
c = 0;
y1 = 1;
for (int y2 = 1; y2 <= m && c < 4; y2++) {
if (ok(x, i, j, k, y1, y2)) {
c++;
y1 = y2 + 1;
}
}
if (c == 4) return true;
}
}
}
return false;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
}
}
l = 0;
r = 1e6;
while (l < r) {
M = l + r + 1 >> 1;
if (chk(M)) l = M;
else r = M - 1;
}
cout << l << endl;
return 0;
}


参考程序二(枚举+dp):

#include <bits/stdc++.h>
using namespace std;
int f[100], ix, jx, kx, n, m, a[100][100], sum[100][100], ans;
int min(int a, int b) {
if (a < b) return a;
return b;
}
int getsum(int x1, int y1, int x2, int y2) {
return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
}
int getval1(int p, int r) {
int v1 = min(getsum(1, 1, ix, p), getsum(1, p + 1, ix, r));
int v2 = min(getsum(ix + 1, 1, jx, p), getsum(ix + 1, p + 1, jx, r));
int v3 = min(getsum(jx + 1, 1, kx, p), getsum(jx + 1, p + 1, kx, r));
int v4 = min(getsum(kx + 1, 1, n, p), getsum(kx + 1, p + 1, n, r));
return min(min(v1, v2), min(v3, v4));
}
int getval2(int p, int l) {
int v1 = min(getsum(1, p, ix, m), getsum(1, l, ix, p - 1));
int v2 = min(getsum(ix + 1, p, jx, m), getsum(ix + 1, l, jx, p - 1));
int v3 = min(getsum(jx + 1, p, kx, m), getsum(jx + 1, l, kx, p - 1));
int v4 = min(getsum(kx + 1, p, n, m), getsum(kx + 1, l, n, p - 1));
return min(min(v1, v2), min(v3, v4));
}
int calc() {
int j = 1, ans, buf, val;
f[1] = 0;
for (int i = 2; i <= m; i++) {
val = getval1(j, i);
while (j + 1 < i && (buf = getval1(j + 1, i)) >= val) {
j++;
val = buf;
}
f[i] = val;
}
ans = 0;
j = m;
for (int i = m - 1; i >= 2; i--) {
val = getval2(j, i);
while (j - 1 > i && (buf = getval2(j - 1, i)) >= val) {
j--;
val = buf;
}
ans = max(ans, min(f[i - 1], val));
}
return ans;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
}
}
ans = 0;
for (ix = 1; ix < n; ix++) {
for (jx = ix + 1; jx < n; jx++) {
for (kx = jx + 1; kx < n; kx++) {
ans = max(ans, calc());
}
}
}
cout << ans << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  校园招聘 网易 编程