点上的点
Points on the same line
我在做一个练习问题,这是这样的,我们得到了n对坐标(x,y),我们也得到了一个中心点,即(x0,y0))。我们被要求找到最大的点位于(x0,y0)的线上。
我的方法: - 我试图维护一个将斜率作为钥匙的哈希地图,我想获得最大的第二个值,以在同一行上获得最大点数。/p>
mp[(yi-y0)/(xi-x0))]++; //i from 0 to n
And iterating map and doing something line this
if(it->second >max) //it is the iterator
max=it->second;
and printing max at last;
我的方法问题 - 每当我得到(xi-x0)为0时,我会得到运行时错误。我也尝试了Atan(斜率),以便我获得学位,而不是一些未定义的值,但是仍然不起作用。
我期望的 ->如何删除此运行时错误,并且我的方法是在从点(x0,y0)的线上找到最大点的方法。
P.S - 我的母语不是英语>
我假设没有其他点具有与您的"原点"相同的坐标。
如果您的所有坐标恰好是整数,则可以保留一个 Rational 编号(即一对整数,即A Nemerator 和A emnominator )作为坡度,而不是一个真实的数字。
斜率是DeltaY / DeltaX
,因此您要做的就是将这对数字分开。您只需要小心地将双人划分为他们的最大的常见除数,然后处理DeltaX
为零的情况。例如:
pair<int, int> CalcSlope (int x0, int y0, int x1, int y1)
{
int dx = abs(x1 - x0), dy = abs(y1 - y0);
int g = GCD(dx, dy);
return {dy / g, dx / g};
}
现在只使用CalcSlope()
的返回值作为您的地图密钥。
如果您需要它,这是计算GCD的一种方法:
int GCD (int a, int b)
{
if (0 == b) return a;
else return gcd(b, a % b);
}
您已经接受了答案,但是我还是想分享我的方法。此方法使用以下事实:三个点a
,b
和c
在且仅当
(a.first-c.first)*(b.second-c.second) - (a.second-c.second)*(b.first-c.first) == 0
您可以使用此属性创建一个自定义比较对象,例如
struct comparePoints {
comparePoints(int x0 = 0, int y0 = 0) : _x0(x0), _y0(y0) {}
bool operator()(const point& a, const point& b) {
return (a.first-_x0)*(b.second-_y0) - (b.first-_x0)*(a.second-_y0) < 0;
}
private:
int _x0, _y0;
};
您可以根据
将其用作地图的比较对象comparePoints comparator(x0, y0);
map<pair<int, int>, int, comparePoints> counter(comparator);
然后,您可以将点添加到此地图上类似于您之前所做的事情:
if (!(x == x0 && y == y0))
counter[{x,y}]++;
通过将comparitor
用作比较对象,如果!comparator(a, b) && !comparator(b,a)
,则在且仅当a
,b
和{x0,y0}
是共线时,地图中的两个键a
, b
被视为相等的。
这种方法的优点是,您无需分割坐标,以避免将舍入错误和零除以零的问题,或计算ATAN,这是一个昂贵的操作。
移动所有内容,以使零点处于原点:
(x i ,y i ) - =(x 0 ,y 0 )
然后,对于每个点(x i ,y i ),找到x i 和y i的最大常见分裂并将两个数字划分为:
k = gcd(x i ,y i )
(x i ',y i `)=(y i /k,y i /k)
现在,在同一射线上的点将映射到等于点。如果(x i ,y i )与(x j ,y j )在同一光线上(x 现在找到最大的相等点集(不要忘记任何(x i ,y i )=(0,0)),您有答案。
您在这里有一个非常原始的方法!
然而,垂直线具有无限的斜率,这是这里的问题:不允许除以0。
构建的替代方案(坡度):
...
int mpvertical=0; // a separate couner for verticals
if (xi-x0)
mp[(yi-y0)/(xi-x0))]++;
else if (yi-y0)
mpvertical++;
// else the point (xi,yi) is the point (x0,y0): it shall not be counted)
这很麻烦,因为您在地图中有所有内容以及此额外的计数器。但这是准确的。解决方法可能是在mp[std::numeric_limits<double>::max()]
中计算此类点,但这将是一个近似值。
注释:情况是xi == x0,yi == y0对应于您的原点。这些点必须属于每条线路时都必须丢弃。
三角替代(角度):
这使用了用于将笛卡尔坐标转换为极坐标的通用atan2公式,以获取角度:
if (xi!=x0 && yi!=y0) // the other case can be ignored
mp[ 2*atan((yi-y0)/((xi-x0)+sqrt(pow(xi-x0,2)+pow(yi-y0,2)))) ]++;
因此,您的MP键将是-pi和 pi之间的角度。没有更多的案例,但计算略有。
您可以隐藏这些额外的详细信息,并在功能中使用更优化的构建:
if (xi!=x0 && yi!=y0) // the other case can be ignored
mp[ atan2(yi-y0, xi-x0) ]++;
您可以尝试此方法
struct vec2
{
vec2(float a,float b):x(a),y(b){}
float x,y;
};
bool isColinear(vec2 a, vec2 b, vec2 c)
{
return fabs((a.y-b.y)*(a.x-c.x) - (a.y-c.y)*(a.x-b.x)) <= 0.000001 ;
}
- 没有找到相关文章