题目:有一个L*W的网格盒子,网格的行编号为0~L-1,网格的列编号为0~W-1。每个格子至多可以放一蛋糕,任意两块蛋糕的欧几里得距离不能等于2。最多可以放多少块蛋糕在网格盒子里?
示意图:(其中1代表有蛋糕,0代表没蛋糕)
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
图1
解法一:
如图一所示我们可以把问题分成网格被4整除、被2整除、其他三类情况
- 被4整除的情况
1 | 1 | 0 | 0 |
1 | 1 | 0 | 0 |
图2
1 | 1 | 0 | 0 |
1 | 1 | 0 | 0 |
0 | 0 | 1 | 1 |
0 | 0 | 1 | 1 |
图3
由图2、3的情况可以发现在能被4整除的情况下,蛋糕最多能够放下整个网格数量的一半(W*L/2)。
- 被2整除的情况
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
图4
由图4的情况可以发现在能被2整除的情况下,蛋糕最多能够放下(W*L/4+1)*2。
网格为奇数的情况
1 1 0 1 1 0 0 0 1 图5
网格为奇数的情况下,蛋糕最多能放下(W*L)/2+1.
致此,本题的情况全部讨论结束,时间复杂度为O(1),程序实例:
#include<iostream>
using namespace std;
int main() {
int W, L, counts = 0;//W为网格长,L,为网格的宽
cin >> L >> W;
if (W % 4 == 0 || L% 4 == 0) {//能被4整除
counts = W*L / 2;
}else if(W % 2 == 0 && L % 2 == 0) {//能被2整除
counts = (W*L / 4 + 1) * 2;
}
else {
counts = W*L / 2 + 1;//网格为奇数
}
cout << counts << endl;
system("pause");
return 0;
}
解法二:
由上图可知,网格中蛋糕的排列顺序有规则:
110011001100
110011001100
001100110011
001100110011
其中,网格的行数被4整除余0或者1(即 L%4=0或者L%4=1)以1100四个数为单元循环;
网格的行数被4整除余2或者3(即 L%4=2或者L%4=3)以0011四个数为单元循环.
#include<iostream>
#include<vector>
using namespace std;
int main() {
int L, W;
int count = 0;
cin >> L >> W;
for (int i = 0; i < L; i++) {
if (i % 4 == 0 || i % 4 == 1) {
for (int j = 0; j < W; j++) {
if (j % 4 == 0 || j % 4 == 1) {
count++;
}
}
}
else {
for (int j = 0; j < W; j++) {
if (j % 4 == 2 || j % 4 == 3) {
count++;
}
}
}
}
cout << count << endl;
return 0;
}