点在同一行

时间:2015-05-05 05:03:24

标签: c++ geometry maps runtime-error

我正在做一个练习题,它是这样的,我们给了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(斜率)这样我就得到度数而不是某些未定义的值但是仍然无法正常工作。

我的期望 - &gt;如何删除此运行时错误,我的方法是正确的,可以找到从点(x0,y0)传递的线上的最大点。

P.S - 我母语不是英语所以如果出现问题请不要理会。我尽力使一切都清楚如果我不够清楚请告诉我

5 个答案:

答案 0 :(得分:3)

您已经接受了答案,但无论如何我想分享我的方法。此方法使用以下事实:abc三个点是协变的,当且仅当

(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作为比较对象,如果a,则地图中的两个键b!comparator(a, b) && !comparator(b,a)被视为相等,当且仅当a时才为真1}},b{x0,y0}是共线的。

这种方法的优点是你不需要划分坐标以避免舍入误差和除以零的问题,或计算atan这是一项代价高昂的操作。

答案 1 :(得分:2)

我假设没有其他点与你的“原点”具有相同的坐标。

如果你的所有坐标都是整数,你可以保留一个有理数字(即一对整数,即分子分母)作为斜率,而不是单个实数。

斜率为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);
}

答案 2 :(得分:1)

你这里有一个非常原创的方法!

然而,垂直线具有无限斜率,这是问题所在:不允许除以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 AND yi == y0对应于您的原点。这些点必须被丢弃,因为它们属于每一条直线。

Trigonomic替代(角度):

这使用用于将笛卡尔坐标转换为极坐标的一般atan2 formula来获得角度:

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之间的角度。没有更多的额外情况,但更多的计算。

您可以隐藏这些额外的细节,并使用更加优化的build in function

if (xi!=x0 && yi!=y0)  // the other case can be ignored 
    mp[ atan2(yi-y0, xi-x0) ]++;

答案 3 :(得分:1)

移动所有内容,使零点位于原点:

(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)< / p>

现在,同一光线上的点将映射到相等的点。如果(x i ,y i )与(x j ,y j )在同一条光线上,则(x i ',y i ')=(x j ',y j ')。

现在找到最大的相等点集(不要忘记任何(x i ,y i )=(0,0))并且你有答案

答案 4 :(得分:0)

你可以尝试这种方法

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 ;
}