【JZOJ】【二分】蛋糕

早过忘川 提交于 2019-12-14 05:07:40

LinkLink

JZOJJZOJ 39183918

DescriptionDescription

今天是Bessie的生日,他买了一个蛋糕和朋友们一起分享,蛋糕可以看成是一个R行C列的表格,共有R*C个格子,每个格子都有一个0至9的数字,表示该格子蛋糕拥有的巧克力。现在Bessie要把蛋糕横的切3刀再竖的切3刀,由于Bessie刀法厉害,所以每个格子蛋糕都是完整的,显然蛋糕会被切成16份,然后Bessie和他的15个朋友们每人拿一份,Bessie比较客气,总是等其他朋友拿完了,Bessie拿最后剩下的那一份。Bessie的朋友们都很不客气,都是挑最多巧克力的那份去拿,于是Bessie最后拿到手的那份蛋糕总是巧克力总和最少的。Bessie心想:既然自己总是最后拿蛋糕,那应该怎么切蛋糕,才能使得自己拿的那部分蛋糕的有尽量多的巧克力呢?这个问题自然是你的任务了。

InputInput

第一行,个两整数R,C。
接下来有R行,每行有C个整数,每个整数范围是0至9。

OutputOutput

一个整数,表示Bessie最后拿到的蛋糕最多可以有多少巧克力。

SampleSample InputInput

5 5
95998
21945
23451
99798
74083

SampleSample OutputOutput

3

HintHint

40%的数据, 4 <= R,C <= 10。
60%的数据,  4 <= R,C <= 20。
100%的数据, 4 <= R,C <= 75。

以下是最优的一种切割方法

9 | 5 | 9 9 | 8
--|---|-----|--
2 | 1 | 9 4 | 5
2 | 3 | 4 5 | 1
--|---|-----|--
7 | 4 | 0 8 | 3

TrainTrain ofof ThoughtThought

我们先暴力枚举竖着切的,然后在每一种竖着切的方案里面二分横着切之后形成的块数的所含巧克力最小值(也就是答案),若当前横切一刀可以满足,就切,然后这样一步步判断,取最大值

CodeCode


#include<iostream>
#include<cstdio>

using namespace std;

int r, c, t, ans = -1e9, s[80][80], a[80][80];

bool check(int cut1, int cut2, int cut3, int mid)
{
	int p1, p2, p3, p4;
	int cutx = 0, cutnum = 0;
	for (int i = 1; i <= r; ++i)
	{
		p1 = s[i][cut1] - s[cutx][cut1];
		p2 = s[i][cut2] - s[i][cut1] - s[cutx][cut2] + s[cutx][cut1];
		p3 = s[i][cut3] - s[i][cut2] - s[cutx][cut3] + s[cutx][cut2];
		p4 = s[i][c] - s[i][cut3] - s[cutx][c] + s[cutx][cut3];//计算竖着切了之后的值
		if (p1 >= mid && p2 >= mid && p3 >= mid && p4 >= mid && cutnum != 3) {
			cutx = i;
			cutnum++;
			continue;
		}//判断是否能横切
		if (cutnum == 3) break;
	}
	if (cutnum < 3) return 0;
	if (cutnum == 3) {
		p1 = s[r][cut1] - s[cutx][cut1];
		p2 = s[r][cut2] - s[r][cut1] - s[cutx][cut2] + s[cutx][cut1];
		p3 = s[r][cut3] - s[r][cut2] - s[cutx][cut3] + s[cutx][cut2];
		p4 = s[r][c] - s[r][cut3] - s[cutx][c] + s[cutx][cut3];
		if (p1 >= mid && p2 >= mid && p3 >= mid && p4 >= mid) return 1;
		 else return 0;
	}//求最后切完三刀后的四块是否满足
	return 0;
}

int main()
{
	char ch;
	scanf("%d%d", &r, &c); getchar();
	for (int i = 1; i <= r; ++i) 
	{ 
		for (int j = 1; j <= c; ++j)
		{
			scanf("%1d", &a[i][j]);
		}	
	}
	for (int i = 1; i <= r; ++i)
	 for (int j = 1; j <= c; ++j)
	 	s[i][j] = a[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
	for (int l1 = 1; l1 < c - 2; ++l1)
	 for (int l2 = l1 + 1; l2 < c - 1; ++l2)
	  for (int l3 = l2 + 1; l3 < c; ++l3)
	  {
	  		int l = 0, right =s[r][c];
	  		while (l < right)
	  		{
	  			int mid = (l + right + 1) >> 1;
	  			if (!check(l1, l2, l3, mid)) right = mid - 1;
	  			 else l = mid;
	  		}
	  		ans = max(ans, l);
	  }		
	printf("%d", ans);
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!