微软编程之美大赛-长方形个数问题

时间:2014.04.05

地点:基地二楼

---------------------------------------------------------------------

一、简述

  这是2013年微软编程之美大赛资格赛的题目。

---------------------------------------------------------------------

时间限制: 1000ms 内存限制: 256MB

2.题目

在 N 条水平线与 M 条竖直线构成的网格中,放 K 枚石子,每个石子都只能放在网格的交叉点上。问在最优的摆放方式下,最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。

3.要求

输入文件包含多组测试数据。

第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。

每组数据为三个用空格隔开的整数 N,M,K。

4.输出

对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示最多能找到的符合条件的长方形数量。所有数据按读入顺序从1开始编号。

5.数据范围

1 ≤ T ≤ 100

0 ≤ K ≤ N * M

小数据:0 < N, M ≤ 30

大数据:0 < N, M ≤ 30000

6.样例输入

3
3 3 8
4 5 13
7 14 86

7.样例输出

Case #1: 5
Case #2: 18
Case #3: 1398

---------------------------------------------------------------------

三、思路

  我的想法是,先对给定的点数K开根号,因为我们有限制K<=N*M,所以K在网格中总是放得下的,将K开根号后的值与N、M中的最小值做比较,如果根号值小,而当点形成一个方正时总是能获得最多矩形数,所以我们尽量向方正靠拢,于是可先计算所得方正形成的矩形数,然后将剩余的点依次往方正后面补,计算第二部分新形成的矩形数。还有一种情况是当根号值大于或等于最小边长时,这时我们不能按根号值形成方正,但可按最小边长形成一个矩形,第一部分先计算这个矩形中的矩形数,第二部分和上面一样,将余下的点数往矩形后面追加,并计算新的矩形数即可。代码如下:

#include
#include
#include
using namespace std;
unsigned CalculateGrid(unsigned N, unsigned M, unsigned K);
//Preconditon: N,M fail into [0,30 000] and K fail into [0,N*M]
//Postcondition: Return the max matrix numbers whitch every matrix's edge paralell to grid
bool CheckTheInput(unsigned N, unsigned M, unsigned K);
//Precondition: Check the parameters' leagal
//Postcondition: Return true when every parameter is leagal
void PrintTheResult(vector& vec);
//Postcondition: Print this test's result according to the requirements
unsigned CalculateMartrix(unsigned row, unsigned col);
//Precondition: Given a matrix
//Postcondition:Return this matrix's sub_matrixs number
int main()
{
	unsigned T = 0;
	cin >> T;
	assert(T >= 1 && T <= 100);

	unsigned N, M, K;
	vector matrix_count;
	while (T)
	{
		cin >> N>>M>>K;
		assert(CheckTheInput(N, M, K));
		matrix_count.push_back(CalculateGrid(N, M, K));
		--T;
	}
	PrintTheResult(matrix_count);
	return 0;
}
unsigned CalculateMartrix(unsigned row, unsigned col)
{
	return row*col*(row - 1)*(col - 1) / 4;
}
unsigned CalculateGrid(unsigned N, unsigned M, unsigned K)
{
	unsigned min_edge = N < M ? N : M;
	unsigned squre_root = static_cast(sqrt(K));
	unsigned first_part, second_part, difference;
	if (squre_root 1 && difference <= squre_root)
			second_part = squre_root*difference*(difference - 1) / 2;
		else if (difference == squre_root + 1)
			second_part = squre_root*squre_root*(squre_root - 1) / 2;
		else if (difference > (squre_root + 1))
			second_part = squre_root*squre_root*(squre_root - 1) / 2
			+ (difference - squre_root)*(difference - squre_root - 1) / 2;
	}
	else
	{
		unsigned row_count = K / min_edge;
		first_part = CalculateMartrix(min_edge, row_count);
		difference = K - row_count*min_edge;
		second_part = row_count*difference*(difference - 1) / 2;
	}
	return first_part + second_part;
}
bool CheckTheInput(unsigned N, unsigned M, unsigned K)
{
		return (N > 0 && N <= 30000) && (M > 0 && M <= 30000) 
			    && (K >= 1 && K <= N*M);
}
void PrintTheResult(vector& vec)
{
	unsigned count = 1;
	for (auto element : vec)
	{
		cout << "Case#" << count << ": " << element << endl;
		++count;
	}
}

---------------------------------------------------------------------

四、总结

  在完成一个任务之前,要把任何问题任何场景都想清楚,然后再动手编程,这是最省事答案也是最完美的。只有当这些基本情况你都想清楚了的时候,那么代码在你的控制之下,而不是你在代码的控制之下。

你可能感兴趣的:(ACM,编程之美,微软,网格,matrix)