主要思路
先用一个结构体数组存每一个矩形的长和宽,然后直接二分枚举答案
代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int k, n;
struct chocolate
{
int h;
int w;
int s;//这里的s其实并没有用,这是刚开始做的记录一下错误的原因
}a[N];
bool check(int x)
{
int sum = 0;//用来记录可以分得得巧克力的总数
for (int i = 1; i <= n; i++)
{
// if(a[i].h>=x&&a[i].w>=x)//这样写是错的,后面会解释
// sum += a[i].s / (x * x);
sum += (a[i].w / x) * (a[i].h / x);
}
if (sum < k)//巧克力总数不够,则需要将每块巧克力的大小变小
return false;
return true;
}
int main()
{
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
int x, y;
cin >> x >> y;
a[i].h = x;
a[i].w = y;
a[i].s = x * y;//不需要
}
int l = 0, r = 1e5 + 1;
while (l + 1 != r)
{
int mid = (l + r) >> 1;
if (check(mid))
l = mid;
else
r = mid;
}
cout << l << endl;
return 0;
}
注意点
1、这里的长和宽也可以分别用两个数组来存,不一定要用结构体来存
2、最最重要的也易错的是check函数里面sum的求法:
刚开始时本人思路是通过计算每块巧克力的面积,想着除以要分得的巧克力的面积就可以得到分了多少个,而且我还特别判断了每块大巧克力的边长够不够切,结果调试了很久
总是遇到一个样例不能过:
50 100
5 4
9 20
8 3
20 7
14 14
17 9
2 11
16 14
8 16
5 13
20 7
19 2
4 8
6 2
2 7
13 10
1 3
8 16
6 20
1 5
11 10
19 7
20 8
11 14
17 8
5 8
3 15
6 19
5 8
3 18
19 16
8 13
20 14
5 7
14 11
20 18
15 18
5 1
13 1
3 5
2 2
15 16
13 11
8 9
8 11
11 3
5 5
16 2
10 20
12 6
这个样例的标准输出是5,而按照我的写法输出是6
然后就一直调试,一步一步看,最后发现我写的代码当小巧克力的边长为6时分到的小巧克力的总数会大于k,但是别人的代码这样分的数量小于k。
最后通过求助大佬,终于明白为什么我这样写有问题
问题分析
来看一个数据:假设原来的巧克力是3×3的正方形,要得到2×2的小巧克力,问可以切几块
如果按注释部分计算即
if(a[i].h>=x&&a[i].w>=x)
sum += a[i].s / (x * x)
sum=(3*3)/(2*2)=2算出来比正确答案多一,这也就解释了为什么上面样例我的答案比正确答案多一,因为按照这种计算方法多计算了
正确计算方法:
sum += (a[i].w / x) * (a[i].h / x);
sum=(3/2)*(3/2)=1,算出来是正确结果
这种计算方法怎么理解?
a[i].w / x表示可以分多少行,a[i].h / x表示可以分多少列
例如当a[i].w =4,a[i].h=6,x=2
可以分得(a[i].w/ x)*(a[i].h/x)=6个小巧克力
这样就可以避免出现多算少算的问题