牛客网2017校招真题编程练习--4.分田地
2018-02-27 15:24
225 查看
牛客网2017校招真题编程练习--4.分田地
#include <iostream>
#include <string>
using namespace std;
int n, m;
const int MAX_LEN = 80;
int lands[MAX_LEN][MAX_LEN];
int sums[MAX_LEN][MAX_LEN];
// calculate the area between upper-left point (star_x, start_y) and lower-right point (end_x, end_y)
int get_area(int start_x, int start_y, int end_x, int end_y)
{
return sums[end_x][end_y] - sums[end_x][start_y]
- sums[start_x][end_y] + sums[start_x][start_y]; //计算lands中左上点(star_x, start_y)和右下点(end_x, end_y)所围田地的价值和
}
bool is_accord_with(int area_value)
{
// traverse three cutting line in the vertical direction
for (int i = 1; i <= m - 3; ++i)
{
for (int j = i + 1; j <= m - 2; ++j)
{
for (int k = j + 1; k <= m - 1; ++k)
{
int areas[4], start_line = 0, content_count = 0;
for (int t = 1; t <= n; ++t)
{
areas[0] = get_area(start_line, 0, t, i);
areas[1] = get_area(start_line, i, t, j);
areas[2] = get_area(start_line, j, t, k);
areas[3] = get_area(start_line, k, t, m);
// meet the condition
if (areas[0] >= area_value && areas[1] >= area_value &&
areas[2] >= area_value && areas[3] >= area_value) //当前横一刀满足条件
{
start_line = t;
++content_count;
}
}
if (content_count >= 4) //表明当前x是16块田地中最小的,返回true
{
return true;
}
}
}
}
return false;
}
int main() {
cin >> n >> m;
string s;
for (int i = 1; i <= n; ++i) {
cin >> s;
for (int j = 1; j <= m; ++j) {
lands[i][j] = s[j - 1] - '0'; //字符-字符'0'的ASCII码得到数值
sums[i][j] = sums[i][j - 1] + sums[i - 1][j] - sums[i - 1][j - 1] + lands[i][j]; //sum[i][j]表示坐标(i,j)左上方价值总和
}
}
int ans = 0;
int left = 0, right = sums
[m]; // sum
[m]表示所有价值总和
while (left <= right) //二分答案,判断可行性时暴力枚举三列的情况,然后横着贪心地扫一遍,每当四个都满足时就砍一刀,满足四次
//即可,复杂度O(N^4logN)
{
int mid = left + ((right - left) >> 1);
if (is_accord_with(mid)) // 表明mid是16块田地最小的
{
ans = mid;
left = mid + 1;
}
else {
right = mid - 1;
}
}
cout << ans << endl;
system("pause");
return 0;
}
知识点:
1. 二分法
参考博客1:浅谈--二分查找
参考博客2:二分查找各种情况大总结
参考博客3:二分查找
2. //字符-字符'0'的ASCII码得到数值
#include <iostream>
#include <string>
using namespace std;
int n, m;
const int MAX_LEN = 80;
int lands[MAX_LEN][MAX_LEN];
int sums[MAX_LEN][MAX_LEN];
// calculate the area between upper-left point (star_x, start_y) and lower-right point (end_x, end_y)
int get_area(int start_x, int start_y, int end_x, int end_y)
{
return sums[end_x][end_y] - sums[end_x][start_y]
- sums[start_x][end_y] + sums[start_x][start_y]; //计算lands中左上点(star_x, start_y)和右下点(end_x, end_y)所围田地的价值和
}
bool is_accord_with(int area_value)
{
// traverse three cutting line in the vertical direction
for (int i = 1; i <= m - 3; ++i)
{
for (int j = i + 1; j <= m - 2; ++j)
{
for (int k = j + 1; k <= m - 1; ++k)
{
int areas[4], start_line = 0, content_count = 0;
for (int t = 1; t <= n; ++t)
{
areas[0] = get_area(start_line, 0, t, i);
areas[1] = get_area(start_line, i, t, j);
areas[2] = get_area(start_line, j, t, k);
areas[3] = get_area(start_line, k, t, m);
// meet the condition
if (areas[0] >= area_value && areas[1] >= area_value &&
areas[2] >= area_value && areas[3] >= area_value) //当前横一刀满足条件
{
start_line = t;
++content_count;
}
}
if (content_count >= 4) //表明当前x是16块田地中最小的,返回true
{
return true;
}
}
}
}
return false;
}
int main() {
cin >> n >> m;
string s;
for (int i = 1; i <= n; ++i) {
cin >> s;
for (int j = 1; j <= m; ++j) {
lands[i][j] = s[j - 1] - '0'; //字符-字符'0'的ASCII码得到数值
sums[i][j] = sums[i][j - 1] + sums[i - 1][j] - sums[i - 1][j - 1] + lands[i][j]; //sum[i][j]表示坐标(i,j)左上方价值总和
}
}
int ans = 0;
int left = 0, right = sums
[m]; // sum
[m]表示所有价值总和
while (left <= right) //二分答案,判断可行性时暴力枚举三列的情况,然后横着贪心地扫一遍,每当四个都满足时就砍一刀,满足四次
//即可,复杂度O(N^4logN)
{
int mid = left + ((right - left) >> 1);
if (is_accord_with(mid)) // 表明mid是16块田地最小的
{
ans = mid;
left = mid + 1;
}
else {
right = mid - 1;
}
}
cout << ans << endl;
system("pause");
return 0;
}
知识点:
1. 二分法
参考博客1:浅谈--二分查找
参考博客2:二分查找各种情况大总结
参考博客3:二分查找
2. //字符-字符'0'的ASCII码得到数值
相关文章推荐
- 牛客网2017校招真题编程练习--3.下厨房
- 牛客网2017校招真题编程练习--1.合唱团
- 牛客网2017校招真题编程练习--5.分苹果
- 牛客网2017校招真题编程练习--7.藏宝图
- 牛客网2017校招真题编程练习--6.星际穿越
- 2016校招真题编程练习——微信红包(腾讯)
- 牛客网编程练习之京东2017校招题:幸运数
- 牛客网编程练习之网易2017校招题:数字翻转
- 【真题】京东2017校招编程题 幸运数
- 【newCoder】2016校招真题在线编程 风口的猪-中国牛市
- 2017校招真题编程训练--电话号码分身
- 2017校招真题编程训练--丢失的三个数 素数对 n个数最小的k个
- 【真题】京东2017校招编程题 集合
- 华为2017年8月30日校招编程真题01-数字的中文拼音和英文单词之间互相转换
- 2017校招真题编程训练--水仙花树
- 2017校招真题编程训练--幸运数 进制转换
- 2017校招真题在线编程
- 牛客网编程练习之网易2017校招题:下厨房
- 华为2017年8月30日校招编程真题2-自定义的26进制和十进制之间互相转换
- 2017校招真题编程训练--求数列的和