暴力枚举刷题1

题目来源:统计方形(数据加强版) - 洛谷
参考书籍:《深入浅出程序设计竞赛(基础篇)》

解题思路:这道理适合用暴力枚举求解。我把书上提到的四种枚举方法分享给大家。

解题1:减少枚举量

以某个坐标为顶点,统计其正方形和长方形。

#include
#include

using namespace std;

typedef long long LL;

int main()
{
	LL n, m,squ = 0,rec = 0;
	cin >> n >> m;
	for (LL x = 0; x <= n; x++)
	{
		for (LL y = 0; y <= m; y++)
		{
			LL tmp = min(x, y) + min(y, n - x) + min(n - x, m - y) + min(m - y, x);
			squ += tmp;
			rec += n * m - tmp; //长方形
		}
	}
	printf("%lld %lld", squ / 4, rec / 4);
	return 0;
}

解题2 :去掉重复情况,只枚举方形的右下角顶点。

#include
#include

using namespace std;

typedef long long LL;

int main()
{
	LL n, m, squ = 0, rec = 0;
	cin >> n >> m;
	for (LL x = 0; x <= n; x++)
	{
		for (LL y = 0; y <= m; y++)
		{
			LL tmp = min(x, y);
			squ += tmp;
			rec += x * y - tmp; //长方形
		}
	}
	printf("%lld %lld", squ , rec);
	return 0;
}

解题3:枚举其他要素。枚举方形的边长,其实就是统计n ✖m的大矩形中包含多少个边长为a ✖b的小矩形。答案:(n - a + 1) *(m - b +1)

#include
#include

using namespace std;

typedef long long LL;



int main()
{
	LL n, m, squ = 0, rec = 0;
	cin >> n >> m;
	for (LL x = 1; x <= n; x++)
	{
		for (LL y = 1; y <= m; y++)
		{
			if (x == y)
			{
				squ += (n - x + 1) * (m - y + 1);//正方形
			}
			else
			{
				rec += (n - x + 1) * (m - y + 1);//长方形
			}
		}
	}
	printf("%lld %lld", squ, rec);
	return 0;
}

解题 4 :减少枚举量

在这个问题中,我们需要确定一个 n ✖m 方格的矩形包含多少个正方形和长方形(不包含正方形)。为了计算这个,我们可以用以下方法:

  1. 计算正方形的数量:

    • 对于一个 n ✖m 的矩形,最小的正方形是 1×1 的方格,然后是 2×2,直到 min(n,m)×min(n,m)。
    • 所以,1×1 的正方形有 n×m 个。
    • 2×2 的正方形有 (n−1)×(m−1) 个,以此类推。
    • 总正方形的数量是\sum_{i=1}^{min(n,m)}(n-i+1)(m-i+1)

    2  .计算长方形的数量:

       在一个 n×m 的矩形上,计算所有可能的长方形(包括正方形)的数量,可以通过计算所有可能的顶点对来完成。每个长方形由其对角线上的两个顶点唯一确定。要形成一个长方形,我们需要选择两个不同的水平坐标和两个不同的垂直坐标。

  1. 选择水平坐标:在长度为 n 的矩形,有 n+1 个水平的格线。从这n+1 个格线中选择两个不同的格线作为长方形的上下边界,可以有 C(n+1,2) 种选择方法,这是因为顶点对的选择是组合而不是排列(顺序不重要)。

  2. 选择垂直坐标:同理,在宽度为 m 的矩形,有m+1 个垂直的格线。选择两个不同的垂直格线作为长方形的左右边界,可以有 C(m+1,2) 种选择方法。

  3. 计算组合:要形成一个长方形,我们需要同时选择水平和垂直坐标,所以这两种选择的组合数是乘积形式的:C(n+1,2)×C(m+1,2)。

  4. 化简组合公式:组合公式 C(x,2)=x(x−1)​ /2可以应用于这两个选择,所以总的可能的长方形数量是:\frac{(n+1)}{2}n *\frac{(m+1)}{2}m=\frac{n*m(n+1)(m+1)}{4}

#include
#include

using namespace std;

typedef long long LL;

int main()
{
	LL n, m, squ = 0, rec = 0;
	cin >> n >> m;
	for (LL x = 1; x <= min(n,m); x++)
	{
		squ += (n - x + 1) * (m - x + 1) ;//正方形					
	}
	rec  = n * m* (n + 1) * (m+ 1) /4 - squ ;//长方形
	printf("%lld %lld", squ, rec);
	return 0;
}

你可能感兴趣的:(暴力枚举,算法,数据结构,c++,c语言,开发语言)