Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 计算阵列中共线的三元组数_C++_Algorithm - Fatal编程技术网

C++ 计算阵列中共线的三元组数

C++ 计算阵列中共线的三元组数,c++,algorithm,C++,Algorithm,有人问我这个面试问题(C++,algos),我不知道如何解决它 给定一个数组,即包含N个不同点的笛卡尔坐标的Arr[N]计算三元组的数量(Arr[p],Arr[Q],Arr[R]),使得p

有人问我这个面试问题(C++,algos),我不知道如何解决它

给定一个数组,即包含N个不同点的笛卡尔坐标的Arr[N]计算三元组的数量(Arr[p],Arr[Q],Arr[R]),使得p
有什么想法吗?我可以使用什么算法来实现这一点?

如果是二维点:如果(p,Q),(p,R)定义了相同的斜率,那么3个点(p,Q,R)是共线的

m = (p.x - q.x) / (p.y - q.y)  ; slope

不知何故,你需要检查所有可能的组合,并检查,一个有效的算法是技巧,因为第一个简单的是N*(N-1)*(N-2).

我有这个解决方案告诉你是否有更好的

根据它们与x轴或任何其他所需轴(O(n*logn))的斜率对所有点进行排序。现在你要做的就是通过排序列表,找到具有相同斜率的点,无论是正方向还是负方向(这可以在线性时间内完成,即O(n))。假设你在一个例子中得到m个这样的点,然后将答案增加C(m,3)

总时间取决于实现C(m,3)的程度

但渐近O(N logN)


编辑:看到icCube的评论后,我意识到我们不能取任何轴。因此,对于上面定义的算法,将斜率计算点作为n个点之一(因此n次)应该是我的最佳猜测。但是它使算法N*N*Log(N)

以下可能没有优化,但其复杂性是面试官要求的

首先为每对点(N²复杂性)创建一个(a、b、c)值列表 -->(a,b,c)表示直线的笛卡尔方程a*x+b*y+c=0 给定两个点及其坐标(xa,ya)和(xb,yb),计算(a,b,c)很简单。 要么你能找到解决问题的办法

ya=alpha*xa+beta  
yb=alpha*xb+beta

(if (xb-xa) != 0)
alpha = (yb-ya)/(xb-xa)
beta = ya - alpha*xa
a = alpha
b = -1
c = beta

然后,可以将可解方程组改写为更一般的形式

a*x+b*y+c = 0
然后对列表进行排序(N²日志(N²)复杂性,因此N²日志(N)复杂性)

迭代列表中的元素。如果两个连续元素相等,则对应点共线。N²复杂性

您可能希望添加最后一个操作来过滤重复的结果,但您应该很好,并且考虑到复杂性

编辑:我对算法进行了一些更新,同时对其进行了编码,使其更加简单和优化。来了

#include <map>
#include <set>
#include <vector>
#include <iostream>

struct StraightLine
{
    double a,b,c;
    StraightLine() : a(0.),b(0.),c(0.){}
    bool isValid() { return a!=0. || b!= 0.; }
    bool operator<(StraightLine const& other) const
    {
        if( a < other.a ) return true;
        if( a > other.a ) return false;
        if( b < other.b ) return true;
        if( b > other.b ) return false;
        if( c < other.c ) return true;
        return false;
    }
};

struct Point { 
    double x, y; 
    Point() : x(0.), y(0.){}
    Point(double p_x, double p_y) : x(p_x), y(p_y){}
};

StraightLine computeLine(Point const& p1, Point const& p2)
{
    StraightLine line;
    if( p2.x-p1.x != 0.)
    {
        line.b = -1;
        line.a = (p2.y - p1.y)/(p2.x - p1.x);
    }
    else if( p2.y - p1.y != 0. )
    {
        line.a = -1;
        line.b = (p2.x-p1.x)/(p2.y-p1.y);
    }
    line.c = - line.a * p1.x - line.b * p1.y;
    return line;
}

int main()
{
    std::vector<Point> points(9);
    for( int i = 0 ; i < 3 ; ++i )
    {
        for( int j = 0; j < 3 ; ++j )
        {
            points[i*3+j] = Point((double)i, (double)j);
        }
    }


    size_t nbPoints = points.size();
    typedef std::set<size_t> CollinearPoints;
    typedef std::map<StraightLine, CollinearPoints> Result;
    Result result;

    for( int i = 0 ; i < nbPoints ; ++i )
    {
        for( int j = i + 1 ; j < nbPoints ; ++j )
        {
            StraightLine line = computeLine(points[i], points[j]);
            if( line.isValid() )
            {
                result[line].insert(i);
                result[line].insert(j);
            }
        }
    }

    for( Result::iterator currentLine = result.begin() ; currentLine != result.end(); ++currentLine )
    {
        if( currentLine->second.size() <= 2 )
        {
            continue;
        }
        std::cout << "Line";
        for( CollinearPoints::iterator currentPoint = currentLine->second.begin() ; currentPoint != currentLine->second.end() ; ++currentPoint )
        {
            std::cout << " ( " << points[*currentPoint].x << ", " << points[*currentPoint].y << ")";
        }
        std::cout << std::endl;
    }
    return 0;
}
#包括
#包括
#包括
#包括
结构直线
{
双a、b、c;
直线()
bool isValid(){返回a!=0。| | b!=0。}
bool运算符其他。a)返回false;
如果(bother.b)返回false;
如果(csecond.size()second.end();++currentPoint)
{

std::cout代替3个循环,即O(n³),预计算两点给出的所有直线的斜率
Arr[p],Arr[Q]
。即O(n²)。然后比较这些斜率

您可以改进在计算期间或之后按斜率对线进行进一步排序的方法,即O(n logn)。之后,查找具有相同斜率的线就是O(n)

但如果您想知道哪些点是共线的,您可能需要通过实现数据结构来为此付出代价

我认为面试问题的关键不是给出完美的算法,而是在一个想法中识别和讨论问题

编辑:

暴力手段:

#include <iostream>
#include <vector>

struct Point { int x, y; };
bool collinear(Point P, Point Q, Point R)
{
  // TODO: have to look up for math ... see icCube's answer
  return false; 
}

int main()
{
  std::vector<Point> v;

  Point a;
  while (std::cin >> a.x >> a.y)
  {
    v.push_back(a);
  }

  int count = 0;
  for (int p = 0; p < v.size(); ++p)
  {
    for (int q = p+1; q < v.size(); ++q)
    {
      for (int r = q+1; r < v.size(); ++r)
      {
        if (collinear(v[p], v[q], v[r])) ++count;
      }
    }  
  }
  std::cout << count << '\n';
  return 0;
}
#包括
#包括
结构点{intx,y;};
布尔共线(点P、点Q、点R)
{
//TODO:必须查找数学…请参阅iCube的答案
返回false;
}
int main()
{
std::向量v;
a点;
而(std::cin>>a.x>>a.y)
{
v、 推回(a);
}
整数计数=0;
对于(int p=0;pstd::cout很容易看出,可以在O(n^2)时间内获得所有点对及其斜率和y截距。因此,输出为:

IndexB斜率Y截距IndexA

当然,我们不会在IndexA=IndexB的位置插入任何条目

让我们对这个表进行索引(IndexB,Slope,Y),这会强制我们将插入作为O(log(n))插入到这个表中

在我们用新记录(B',S',Y',A')填写此表之后,我们检查是否已经有一个元素,使得现有表的B'=A和新记录的B!=A(意味着我们有一个唯一的三元组)匹配斜率和Y截距(意味着共线)。如果是这种情况,则<
#include <iostream>
#include <vector>

struct Point { int x, y; };
bool collinear(Point P, Point Q, Point R)
{
  // TODO: have to look up for math ... see icCube's answer
  return false; 
}

int main()
{
  std::vector<Point> v;

  Point a;
  while (std::cin >> a.x >> a.y)
  {
    v.push_back(a);
  }

  int count = 0;
  for (int p = 0; p < v.size(); ++p)
  {
    for (int q = p+1; q < v.size(); ++q)
    {
      for (int r = q+1; r < v.size(); ++r)
      {
        if (collinear(v[p], v[q], v[r])) ++count;
      }
    }  
  }
  std::cout << count << '\n';
  return 0;
}
#include <iostream>
#include <vector>
#include <set>
#include <stdlib.h>
#include <math.h>

using namespace std;

#define ADD_POINT(xparam,yparam) { point x; x.x = xparam; x.y = yparam; points.push_back(x); };

#define EPSILON .001

class line {
public:
  double slope;
  double y;
  int a;
  int b;

  bool operator< (const line &other) const{
    if(this->a < other.a)
      return true;
    else if(this->a==other.a){
      if(this->slope-other.slope < -EPSILON)
        return true;
      else if(fabs(this->slope-other.slope) < EPSILON){
        if(this->y-other.y < -EPSILON)
          return true;
        else
          return false;
      }else
        return false;
    }else
      return false;
  }

  line(double slope, double y, int a, int b){
    this->slope = slope;
    this->y = y;
    this->a = a;
    this->b = b;
  }

  line(const line &other){
    this->slope = other.slope;
    this->y = other.y;
    this->a = other.a;
    this->b = other.b;
  }
};

class point {
public:
  double x;
  double y;
};

int main(){
  vector<point> points;
  ADD_POINT(0,0);
  ADD_POINT(7,28);
  ADD_POINT(1,1);
  ADD_POINT(2,3);
  ADD_POINT(2,4);
  ADD_POINT(3,5);
  ADD_POINT(3,14);
  ADD_POINT(5,21);
  ADD_POINT(9,35);

  multiset<line> lines;
  for(unsigned int x=0;x<points.size();x++){
    for(unsigned int y=0;y<points.size();y++){
      if(x!=y){ // No lines with the same point
        point a = points[x];
        point b = points[y];
        double slope = (a.y-b.y)/(a.x-b.x);
        double yint;
        yint = a.y-a.x*slope;
        line newline(slope,yint,x,y);
        lines.insert(newline);
      } 
    }
  }

  for(multiset<line>::const_iterator p = lines.begin(); p != lines.end(); ++p){
    //cout << "Line: " << p->a << " " << p->b << " " << p->slope << " " << p->y << endl;
    line theline = *p;
    line conj(theline.slope,theline.y,theline.b,-1);
    multiset<line>::iterator it;
    pair<multiset<line>::iterator,multiset<line>::iterator> ret;
    ret = lines.equal_range(conj);
    for(it = ret.first; it!=ret.second; ++it){
      //cout << "  Find: " << it->a << " " << it->b << " " << it->slope << " " << it->y << endl;
      int a = theline.a;
      int b = theline.b;
      int c = it->b;
      if(a < b && b < c){
        cout << a << " " << b << " " << c << std::endl;
      }
    }
  }


  //cout << points[0].x << std::endl;

}
    import java.util.*;

    public class CollinearTriplets {

        public static void main(String[] args) {
            Point2d A[] = new Point2d[8];
            A[0] = new Point2d(0, 0);
            A[1] = new Point2d(1, 1);
            A[2] = new Point2d(2, 2);
            A[3] = new Point2d(3, 3);
            A[4] = new Point2d(3, 2);
            A[5] = new Point2d(4, 2);
            A[6] = new Point2d(5, 1);
            A[7] = new Point2d(4, 4);

            System.out.println(countCollinear(A));
        }


        public static int factorial(int n) {
            int fact = 1;
            for (int i = 1; i <= n; i++) {
                fact = fact * i;
            }
            return fact;
        }

        private static int combinations(int n, int r) {
            return factorial(n) / (factorial(n - r) * factorial(r));
        }

        private static long countCollinear(Point2d[] points) {
            Map<Line, Set<Point2d>> lineToPoints = new HashMap<>();
            long result = 0;

            for (int i = 0; i < points.length; i++) {
                for (int j = i + 1; j < points.length; j++) {
                    double slope = 0d, xIntercept, yIntercept; // Default slope paralell to y-axis
                    if (points[i].x == points[j].x) {
                        slope = Double.MAX_VALUE; // Horizontal slope parallel to x-axis
                    } else if (points[i].y != points[j].y) {
                        xIntercept = points[j].x - points[i].x;
                        yIntercept = points[j].y - points[i].y;
                        slope = yIntercept / xIntercept;
                    }
                    Line currLine = new Line(points[i], slope);
                    if (Objects.isNull(lineToPoints.get(currLine))) {
                        lineToPoints.put(currLine, new HashSet<>());
                    }
                    lineToPoints.get(currLine).add(points[i]);
                    lineToPoints.get(currLine).add(points[j]);
                }

            }
            for (Line line : lineToPoints.keySet()) {
                int size = lineToPoints.get(line).size();
                if (size >= 3) {
                    result = result + combinations(size, 3);
                }
            }
            return result;
        }

        /**
         * Line which contains the starting point and slope so that you can identify exact line
         * equals method is overridden to check whether any new line is coinciding or parallel
         */
        static class Line {
            Point2d point;
            double slope;

            public Line(Point2d point, double slope) {
                this.point = point;
                this.slope = slope;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (!(o instanceof Line)) return false;
                Line line = (Line) o;

                if (line.slope == this.slope)
                    return ((((double) (line.point.y - this.point.y)) / (line.point.x - this.point.x)) == this.slope);
                return false;
            }

            @Override
            public int hashCode() {
                return Objects.hash(slope);
            }
        }

        static class Point2d {
            int x;
            int y;

            public Point2d(int x, int y) {
                this.x = x;
                this.y = y;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (!(o instanceof Point2d)) return false;
                Point2d point2d = (Point2d) o;
                return x == point2d.x &&
                        y == point2d.y;
            }

            @Override
            public int hashCode() {
                return Objects.hash(x, y);
            }
        }
    }