不要二---欧几里得距离求蛋糕数

标题:不要二 | 时间限制:1| 内存限制:32768K 

二货小易有一个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) 
输出描述: 输出一个最多可以放的蛋糕数
                   --NOWCODER.COM 牛客网·互联网名企笔试/面试题库

示例1: 
输入 3 2
输出 4

思路:这道题的就是让两个坐标的差值和不能为2,由此可画出以下的一张表,红色代表可以放蛋糕的坐标。

在这里插入图片描述
解法1:复杂度O(n^2)

做一张二维的表,将每一行每一列的值填进去,1代表可以放蛋糕,0代表不可以。最后统计出1的个数即可。

 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
#include<iostream>
#include<vector>
using namespace std;

int main()
{
	int w, h, res = 0;
	cin >> w >> h;
	vector<vector<int>> a;
	a.resize(w);
	for (auto& e : a)
	{
		e.resize(h, 1);
	}
	for (int i = 0; i < w; i++)
	{
		for (int j = 0; j < h; j++)
		{
			if (a[i][j] == 1)
			{
				res++;// 标记不能放蛋糕的位置     
				if ((i + 2) < w)
				{
					a[i + 2][j] = 0;
				}
				if ((j + 2) < h)
				{
					a[i][j + 2] = 0;
				}
			}
		}
	}
	cout << res;
	return 0;
}

解法2:复杂度O(1)

由表中可以得出一个很简单的规律:当横纵坐标为4的倍数时,可以放的蛋糕数为总格子数的一半,若不是4的倍数,将其扩展为离他最近的4的倍数,比如5—>8 , 7—>8,看图:下面就以5,7为例:

红色代表可以放的位置,蓝色代表纵坐标将要扩展后可放蛋糕的位置,
黄色代表横坐标扩展后可放蛋糕的位置,蓝色代表横纵坐标扩展后可放蛋糕的位置的重叠区域。
x----横坐标需要扩展的长度(3),y----纵坐标需要扩展的长度(1)
xx----横坐标扩展后的长度(8),yy-----纵坐标扩展后的长度(8)
由此可以有:
最终可放蛋糕的位置数 =
(扩展后的横坐标 *扩展后的纵坐标)/ 2  
-((横坐标需要扩展的长度 * 纵坐标扩展后的长度)+(纵坐标需要扩展的长度 * 横坐标扩展后的长度))/2 + (重叠区域的可放蛋糕的格子数)
= (xx*yy)/2 - ((x*yy)+(y*xx))/2 + 重叠区域的可放蛋糕的格子数
= 32 - 16 + 2
= 18

最难的地方就是如何求得重合部分的可放蛋糕的格子数。

在这里插入图片描述
以下为求重合部分的可放蛋糕的格子数的几种情况,列举出即可:

1.当横纵坐标某一个不需扩展,或两个都不需扩展时,不存在重合区域,直接减去扩展超出那部分即可。
在这里插入图片描述

2、当纵横坐标需要扩展的长度都在1—2之间时,要加上的重叠区域大小为x*y。
在这里插入图片描述

3、纵横坐标都扩展3时,重叠区域就变成了5。
在这里插入图片描述

4、纵横坐标扩展长度一个为1,另一个为3时,重叠区域固定为2。在这里插入图片描述

5、最后一种情况:横纵坐标扩展长度分别为2和3时,重叠区域固定为4。
在这里插入图片描述

代码实现:

int main()//O(1)算法
{
	int W, H;
	cin >> W >> H;
	int x = W;
	int y = H;
	x = (x % 4 == 0 ? 0 : (4 - (x % 4)));//需要扩展多少坐标数
	y = (y % 4 == 0 ? 0 : (4 - (y % 4)));
	int xx = x + W;//扩展后的纵横坐标,为4的倍数
	int yy = y + H;
	int block = (xx * yy) / 2;//所求的格子数为纵横坐标乘积的一般,先减去扩展的那部分,最后加上扩展重合的部分
	block -= (x * yy + y * xx) / 2;
	if (x == 0 || y == 0)//没有扩展,无需减去重叠区域
	{
		//do nothing
	}

	else if (x <= 2 && y <= 2)//x y = (1,2)
	{
		block += x * y;
	}
	else if (x == 1 && y == 3 || x == 3 && y == 1)//x y =(1,3)
	{
		block += 2;
	}

	else if (x == 3 && y == 3)
	{
		block += 5;
	}

	else//x==2/3 && y==3/2
	{
		block += 4;
	}
	cout << block << endl;
	system("pause");
	return 0;
}
发布了77 篇原创文章 · 获赞 16 · 访问量 6517

猜你喜欢

转载自blog.csdn.net/weixin_43886592/article/details/103051868