问题描述
http://www.nowcoder.com/questionTerminal/1183548cd48446b38da501e58d5944eb
二货小易有一个W*H的网格盒子,网格的行编号为0~H-1,网格的列编号为0~W-1。每个格子至多可以放一块蛋糕,任意两块蛋糕的欧几里得距离不能等于2。
对于两个格子坐标(x1,y1),(x2,y2)的欧几里得距离为:
( (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) ) 的算术平方根
小易想知道最多可以放多少块蛋糕在网格盒子里。
输入描述:
每组数组包含网格长宽W,H,用空格分割.(1 ≤ W、H ≤ 1000)
输出描述:
输出一个最多可以放的蛋糕数
输入例子:
3 2
输出例子:
4
笔记
代码1是自己用回溯法写的,这种问题用回溯法完全应付不来规模变大的情况啊。规模变大肯定算不完。
代码2是参考牛客网上牛客9885763号
的答案。
其实就是一个数学问题,分整除4,整除2,奇数等几种情况讨论即可。蛋糕位置就是间隔每个2*2的正方形的区域。
情况1:
如果W和H有一个能被4整除,可以发现,放下的正好是整个区域的一半。
W和H都能被4整除
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 |
W和H只有1个能被4整除
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
---|---|---|---|---|---|---|---|
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
或者
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
---|---|---|---|---|---|---|---|
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
情况2:
W和H都不能被4整除,但同时能被2整除。
1 | 1 |
---|---|
1 | 1 |
或者
1 | 1 | 0 | 0 | 1 | 1 |
---|---|---|---|---|---|
1 | 1 | 0 | 0 | 1 | 1 |
或者
1 | 1 | 0 | 0 | 1 | 1 |
---|---|---|---|---|---|
1 | 1 | 0 | 0 | 1 | 1 |
0 | 0 | 1 | 1 | 0 | 0 |
0 | 0 | 1 | 1 | 0 | 0 |
1 | 1 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 0 | 1 | 1 |
这种情况,可以W*H/4
求出一个多少个2*2大正方形格子。可以看到1个大格子中取1个,3个大格子中取2个,9个大格子中取5个,对应的关系式W*H/4/2+1
,最后小格子的数目再*4,就是(W*H/4/2+1)*4
。
情况3
W和H都不能被4整除,也不能同时被2整除。
1 |
---|
1 |
或者
1 | 1 | 0 | 0 | 1 |
---|---|---|---|---|
1 | 1 | 0 | 0 | 1 |
或者
1 | 1 | 0 |
---|---|---|
1 | 1 | 0 |
或者
1 | 1 | 0 |
---|---|---|
1 | 1 | 0 |
0 | 0 | 1 |
发现规律
W*H->答案
1->1
2->2
6->4
9->5
即
W*H->(W*H/2+1)
代码1回溯法
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
void place(vector<vector<bool> > &map, int i, int j, const int W, const int H, int &cnt, int &res)
{
bool up = (i-2>=0 && j>=0 && i-2<W && j<H && map[i-2][j]);//上边放了
bool down = (i+2>=0 && j>=0 && i+2<W && j<H && map[i+2][j]);//下边放了
bool left = (i>=0 && j-2>=0 && i<W && j-2<H && map[i][j-2]);//左边放了
bool right = (i>=0 && j+2>=0 && i<W && j+2<H && map[i][j+2]);//右边放了
if (up || down || left || right)//任意一个方向放了就不能放
{
printf("can not place in (%d, %d)\n", i, j);
if (i == W-1 && j == H-1)//放到最后一个结束了
{
printf("\n#end here, cnt = %d, res = %d\n\n", cnt, res);
return;
}
else if (i != W-1 && j == H-1)//换行
place(map, i+1, 0, W, H, cnt, res);
else if (j != H-1)
place(map, i, j+1, W, H, cnt, res);
else
;
}
else//可以选择放也可以选择不放
{
for (int p = 0; p < 2; p++)
{
printf("choose to place %d in (%d, %d)\n", p, i, j);
map[i][j] = bool(p);
cnt += p;
res = max(res, cnt);
if (i == W-1 && j == H-1)//放到最后一个结束了
{
printf("\n#end here, cnt = %d, res = %d\n\n", cnt, res);
return;
}
else if (i != W-1 && j == H-1)//换行
place(map, i+1, 0, W, H, cnt, res);
else if (j != H-1)
place(map, i, j+1, W, H, cnt, res);
else
;
//回溯
cnt -= p;
map[i][j] = bool(1-p);
}
}
}
int main()
{
int W, H;
while(cin >> W >> H)
{
vector<vector<bool> > map(W, vector<bool>(H, false));
int cnt = 0;
int res = 0;
place(map, 0, 0, W, H, cnt, res);
cout << res << endl;
}
return 0;
}
代码2数学分析
#include <iostream>
using namespace std;
int main()
{
int W, H, i, j, cnt = 0;
cin >> W >> H;
if (W % 4 == 0 || H % 4 == 0)
cnt = W * H / 2;
else if (W % 2 == 0 && H % 2 == 0)
cnt = (W * H / 4 / 2 + 1) * 4;
else
cnt = W * H / 2 + 1;
cout << cnt << endl;
return 0;
}
//其实就是一个数学问题,分整除4,整除2,奇数等几种情况讨论即可。蛋糕位置就是间隔每个2*2的正方形的区域。