题目:在 N 条水平线与 M 条竖直线构成的网格中,放 K 枚石子,每个石子都只能放在网格的交叉点上。问在最优的摆放方式下,最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子。
输入:输入文件包含多组测试数据。第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。每组数据为三个用空格隔开的整数 N,M,K。
输出:对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示最多能找到的符合条件的长方形数量。所有数据按读入顺序从1开始编号。
样例输入
-
3 3 3 8 4 5 13 7 14 86
样例输出
-
Case #1: 5 Case #2: 18 Case #3: 1398
刚开始看着题目的时候,没有想法,就单单AC了传话游戏那题;今天在网上看了看别人的思路,发觉其实类似于上周微软笔试那道3*4矩阵中有多少个矩形的题目,恍然大悟;
思路: 转自http://www.cnblogs.com/wuminye/archive/2013/04/07/3006425.html
首先先考虑对于一个布满点的矩形(x行,Y列),所有的矩形总数为 C(2,x)*C(2,y)。要使数量最多,则x和y要尽可能接近(有最大行和最大列的限制)。题中所给的K可能不能刚好排成大矩形,可能有多余的几个点,这几个点的数量一定不会超过一行或一列的最大数量。 试想如果超过,则多出来完整的一行或一列可以和原来的大矩形构成更大的矩形,剩下的点就不能构成完整的一行或一列了。
多余多出来的点,以一排或一列的形式,靠在大矩形短的一边(要注意是否到达边界),设多余K个点,则多增加的矩形数为 C(2,K)*L (L为长边的点数)。
上代码:没有提交过,不晓得对错,自己测试了几组数据是对的;
#include <iostream>
#include <cmath>
using namespace std;
int getNRec(int x)
{
if(x == 1)
return 1;
return x*(x+1)/2;
}
void main()
{
int cnt;
int temp, i, j, remain, res = 0;
int m, n, k, pq = 0;
int width, length;
cin >>cnt;
for(i = 0; i < cnt; i++)
{
res = 0;
cin >>n>>m>>k;
temp = sqrt(k);
if(n < m)
{
j = m;m = n;n = j;
}
width = temp>m?m:temp;
length = (k/width)>n?n:(k/width);
remain = k - width*length;
res = getNRec(width-1)*getNRec(length-1);
cout <<"Case #"<<++pq<<": ";
if(remain >= 2)
{
if(length == n)
{
res += getNRec(remain-1)*getNRec(width) - getNRec(remain-1)*getNRec(width-1);
}
else
{
res += getNRec(remain-1)*getNRec(length) - getNRec(remain-1)*getNRec(length-1);
}
}
cout <<res<<endl;
}
}
看看有没有热心网友大牛,分析下对不对啊~~