题目:二货小易有一个W*H的网格盒子,网格的行编号为0 ~ H-1,网格的列编号为0 ~ W-1。每个格子至多可以放一块蛋糕,任意两块蛋糕的欧几里得距离不能等于2。对于两个格子坐标(x1,y1),(x2,y2)的欧几里得距离为: (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) ) 的算术平方根。小易想知道最多可以放多少块蛋糕在网格盒子里。
引用:引用原文链接
满足欧几里得距离不等于2,则同一行中任意两块蛋糕的距离一定大于等于2或者为0才可以,在任意斜对角线上的蛋糕都不可能满足欧几里得距离为2,贪心思想尽可能实现两个蛋糕一起放
-
先考虑最简单的情况:行数、列数都是 4 的倍数
如图,这是一个 4 × 8 大小的盒子:图中一个黄色圆占了四个空格,这四个空格可以放四块蛋糕并且满足欧几里得距离小于2,放完4块蛋糕蛋再隔两个空再放入, 我把四个格子看成一组
从左上角开始四个一组放蛋糕,每放一组空一组:
由于行列数都是 4 的倍数,而一组蛋糕只要占用两行两列,所以放入的黄点数量必定为偶数个,且放入蛋糕数量和空出的格子数量相等。
若设总格子数为:S = W * H,则放入蛋糕数为 S / 2。
并且,由下面四幅图我们可以推出:只要行数或列数为4的倍数,上式仍然成立(下图中半圆表示两块蛋糕,)
-
如果行数和列数都不是4的整数倍,但是行数列数都为 2 的倍数,我们依然可以将每个盒子用四个一组的蛋糕放满,但是情况和 1 不一样了,于是出现了这种情况:
.
可以发现:黄圈总是比空圈多一个,若设总的组数为 S = W×H÷4,记蛋糕组数为 count,则使用int类型的除法可得,count = (S + 1)/2。蛋糕数即为4倍的count。 -
若只有行数或列数一方为 2 的倍数,另一个为奇数,则会出现某一行或列的黄圈被切了一半的情况,只需要补一个对称的盒子再使用情况2中的方法进行处理即可。 若是行列数都是奇数,同样可以补成2的形式,例如:
如果行和列只有一方是奇数则总的组数为S = W×H×2÷4,count = (S + 1)/2,蛋糕数即为count÷2×4,如果行和列都是奇数则总的组数为S = (W×2)×(H×2)÷4,count = (S + 1)/2,蛋糕数即为count÷4×4
代码实现如下:
由于在计算组数时候容易出现小数,因此在代码中尽量求避免单独的蛋糕组数
#include<stdio.h>
int main(){
int L, H, S, count; //L列,H是行,count组数也用来表示是蛋糕得数量
scanf(("%d %d"),&L,&H );
//行或者列有一方是4的整数倍
if(L% 4 == 0 || H % 4 == 0){
S = L * H;
count = S/2;
//情况2:行和列都是2的整数倍
else if(L % 2 == 0 && H % 2 == 0){
S = L * H / 4;
count = (S + 1) / 2;
count *= 4;
}
//行和列有一方是2的整数倍,另一方奇数
else if(L % 2 == 0 || H % 2 == 0){
//S先乘2把它变成行列都是偶数的情况,再求组数除以4, 转成情况2
S = (L * H *2)/4;
count = (S + 1);
}
//行和列都是奇数
else{
//扩充4倍, 转成情况2
S = (L * 2) * (H * 2) / 4;
count = (S + 1) / 2; //直接计算避免小数出现
}
printf("%d\n",count);
return 0;
}