牛客网2017校招真题--分田地

                                  牛客网2017校招真题--分田地

题目描述

解题思路

代码

#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[n][m];           // sum[n][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码得到数值

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值