百度之星 Apple问题

Apple

Time Limit : 10000/5000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)

Problem Description

小H是一个程序员,但他的生活不局限在写程序。

有一天,他走到公园散步。他见到公园的一棵苹果树上结满了苹果。他于是拿起石头,想砸几个苹果下来当第二天的早餐。突然他思考到了一个问题:怎样才能一次砸到最多苹果?

我们考虑该局面是这样一个模型:所有东西位于二维笛卡尔坐标系,其中小H位于原点,苹果们分别在坐标系的整点上。石头飞出的轨迹是一条经过原点的抛物线,确切的说,经过的是 y=ax^2+bx 的抛物线(a<0)。石头砸到一个苹果后,该苹果会落下,且石头不会改变运动轨迹。

现在小H希望求扔一个石头最多砸到的苹果数。

Input

         第一行为一个整数T(1 <= T<= 10),表示有T组测试数据;

         每组数据第一行一个正整数N(1<=N<=2000),表示苹果数。下面N行每行两个整数给出每个苹果的坐标xi, yi(1<=xi<=1000, 1<=yi<=1000000)。

Output

         对于每组数据,输出最多可能砸到的苹果数。

解法:

    根据题目的描述,题目的意思即是给定一个坐标点集合S,我们需要求出一条形式为y = aX2+ bX的抛物线,使得集合S中的点能够尽可能多的落在这条抛物线上。那么换一个角度思考,对于集合S中的每一个点p = (x, y),我们根据(x, y)求出一个关于a和b的等式,表示为 a = kb + c。这其实可以看作一条以a,b为坐标系的直线。所有以这条直线上的a和b的值作为参数的抛物线都经过点p。假设集合S中总共有n个点,则我们便可以得到n条关于a和b的直线。这样一来,问题便转换为:我们拥有n条直线,要求一个点,使得n条直线中经过这个点的直线条数最多,那么由这个点(a,b)作为系数的抛物线经过集合S的点数最多,具体点数即为通过这个点(a, b)的直线条数。

     分析至此,则写出相应的代码便不是难事。下面给出我的参考代码(仅供参考,望多多指教):

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

#define EPS 0.001

struct Line 
{
	double k;
	double c;
};

struct Point
{
	double x;
	double y;

	bool operator==(const Point& rhs)
	{
		if(x - rhs.x < EPS && y - rhs.y < EPS) return true;
		return false;
	}
};

struct node
{
	Point p;
	int count;
};

int main()
{
	int t;
	int n;
	cin >> t;
	while(t--)
	{
		vector<node> inter;
		vector<Line> lines;
		cin >> n;
		bool flag = true;
		for(int i = 0; i < n; i++)
		{
			int x, y;
			cin >> x >> y;
			Line l;
			l.k = -x;
			l.c = y/x;

			Point p;
			for(vector<Line>::iterator iter = lines.begin(); iter != lines.end(); iter++)
			{
				if(l.k != iter->k || l.c != iter->c) 
					flag = false;
				p.x = (l.c - iter->c) / (iter->k - l.k);
				p.y = (iter->k * l.c - l.k * iter->c) / (iter->k - l.k);

				vector<node>::iterator i;
				for(i = inter.begin(); i != inter.end(); i++)
				{
					if(i->p == p)
					{
						i->count++;
						break;
					}
				}
				if(i == inter.end())
				{
					node newN;
					newN.p = p;
					newN.count = 1;
					inter.push_back(newN);
				}

			}
			lines.push_back(l);
		}

		int max = 0;
		if(!flag)
		{
			for(vector<node>::iterator iter = inter.begin(); iter != inter.end(); iter++)
			{
				if(iter->count > max ) max = iter->count;	
			}
		}
		else
			max = n;
		cout << max << endl;
	}
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值