Given two points in the x, y plane:
x, f(x)
1, 3
2, 5
I can interpolate them using Lagrange and find f(1.5), which result in 4. Thinking a little I managed to find a way to discover the coefficients of the equation:
void l1Coefficients(const vector<double> &x, const vector<double> &y) {
double a0 = y[0]/(x[0]-x[1]);
double a1 = y[1]/(x[1]-x[0]);
double b0 = (-x[1]*y[0])/(x[0]-x[1]);
double b1 = (-x[0]*y[1])/(x[1]-x[0]);
double a = a0 + a1;
double b = b0 + b1;
cout << "P1(x) = " << a << "x +" << b << endl;
}
That gives me P1(x) = 2x +1.
Thinking a little more I was able to extend that to 2nd order equations. So, given the points:
1, 1
2, 4
3, 9
I found the equation P2(x) = 1x^2 +0x +0 with the following:
void l2Coefficients(const vector<double> &x, const vector<double> &y) {
double a0 = y[0] / ((x[0]-x[1])*(x[0]-x[2]));
double a1 = y[1] / ((x[1]-x[0])*(x[1]-x[2]));
double a2 = y[2] / ((x[2]-x[0])*(x[2]-x[1]));
double b0 = -(x[1]+x[2])*y[0] / ((x[0]-x[1])*(x[0]-x[2]));
double b1 = -(x[0]+x[2])*y[1] / ((x[1]-x[0])*(x[1]-x[2]));
double b2 = -(x[0]+x[1])*y[2] / ((x[2]-x[0])*(x[2]-x[1]));
double c0 = (x[1]*x[2])*y[0] / ((x[0]-x[1])*(x[0]-x[2]));
double c1 = (x[0]*x[2])*y[1] / ((x[1]-x[0])*(x[1]-x[2]));
double c2 = (x[0]*x[1])*y[2] / ((x[2]-x[0])*(x[2]-x[1]));
double a = a0 + a1 + a2;
double b = b0 + b1 + b2;
double c = c0 + c1 + c2;
cout << "P2(x) = " << a << "x^2 +" << b << "x +" << c << endl;
}
Working hard I actually was able to find the coefficients for equations of order up to 4th.
How to find the coefficients of order n equations? Where
Pn(x) = c_2x^2 + c_1x^1 + c_0x^0 + ...
It's a simple linear algebra problem.
We have a set of N samples of the form xk -> f(xk) and we know the general form of function f(x), which is:
f(x) = c0x0 + c1x1 + ... + cN-1xN-1
We want to find the coefficients c0 ... cN-1. To achieve that, we build a system of N equations of the form:
c0xk0 + c1xk1 + ... + cN-1xkN-1 = f(xk)
where k is the sample number. Since xk and f(xk) are constants rather than variables, we have a linear system of equations.
Expressed in terms of linear algebra, we have to solve:
Ac = b
where A is a Vandermonde matrix of powers of x and b is a vector of f(xk) values.
To solve such a system, you need a linear algebra library, such as Eigen. See here for example code.
The only thing that can go wrong with such an approach is the system of linear equations being under-determined, which will happen if your N samples can be fit with with a polynomial of degree less than N-1. In such a case you can still solve this system with Moore-Penrose pseudo inverse like this:
c = pinv(A)*b
Unfortunately, Eigen doesn't have a pinv() implementation, though it's pretty easy to code it by yourself in terms of Singular Value Decomposition (SVD).
I created a naive implementation of the matrix solution:
#include <iostream>
#include <vector>
#include <stdexcept>
class Matrix
{
private:
class RowIterator
{
public:
RowIterator(Matrix* mat, int rowNum) :_mat(mat), _rowNum(rowNum) {}
double& operator[] (int colNum) { return _mat->_data[_rowNum*_mat->_sizeX + colNum]; }
private:
Matrix* _mat;
int _rowNum;
};
int _sizeY, _sizeX;
std::vector<double> _data;
public:
Matrix(int sizeY, int sizeX) : _sizeY(sizeY), _sizeX(sizeX), _data(_sizeY*_sizeX){}
Matrix(std::vector<std::vector<double> > initList) : _sizeY(initList.size()), _sizeX(_sizeY>0 ? initList.begin()->size() : 0), _data()
{
_data.reserve(_sizeY*_sizeX);
for (const std::vector<double>& list : initList)
{
_data.insert(_data.end(), list.begin(), list.end());
}
}
RowIterator operator[] (int rowNum) { return RowIterator(this, rowNum); }
int getSize() { return _sizeX*_sizeY; }
int getSizeX() { return _sizeX; }
int getSizeY() { return _sizeY; }
Matrix reduce(int rowNum, int colNum)
{
Matrix mat(_sizeY-1, _sizeX-1);
int rowRem = 0;
for (int y = 0; y < _sizeY; y++)
{
if (rowNum == y)
{
rowRem = 1;
continue;
}
int colRem = 0;
for (int x = 0; x < _sizeX; x++)
{
if (colNum == x)
{
colRem = 1;
continue;
}
mat[y - rowRem][x - colRem] = (*this)[y][x];
}
}
return mat;
}
Matrix replaceCol(int colNum, std::vector<double> newCol)
{
Matrix mat = *this;
for (int y = 0; y < _sizeY; y++)
{
mat[y][colNum] = newCol[y];
}
return mat;
}
};
double solveMatrix(Matrix mat)
{
if (mat.getSizeX() != mat.getSizeY()) throw std::invalid_argument("Not square matrix");
if (mat.getSize() > 1)
{
double sum = 0.0;
int sign = 1;
for (int x = 0; x < mat.getSizeX(); x++)
{
sum += sign * mat[0][x] * solveMatrix(mat.reduce(0, x));
sign = -sign;
}
return sum;
}
return mat[0][0];
}
std::vector<double> solveEq(std::vector< std::pair<double, double> > points)
{
std::vector<std::vector<double> > xes(points.size());
for (int i = 0; i<points.size(); i++)
{
xes[i].push_back(1);
for (int j = 1; j<points.size(); j++)
{
xes[i].push_back(xes[i].back() * points[i].first);
}
}
Matrix mat(xes);
std::vector<double> ys(points.size());
for (int i = 0; i < points.size(); i++)
{
ys[i] = points[i].second;
}
double w = solveMatrix(mat);
std::vector<double> result(points.size(), 0.0);
if(w!=0)
for (int i = 0; i < ys.size(); i++)
{
result[i] = solveMatrix(mat.replaceCol(i, ys));
result[i] /= w;
}
return result;
}
void printCoe(std::vector<double> coe)
{
std::cout << "f(x)=";
bool notFirstSign = false;
for (int i = coe.size() - 1; i >= 0; i--)
{
if (coe[i] != 0.0)
{
if (coe[i] >= 0.0 && notFirstSign)
std::cout << "+";
notFirstSign = true;
if (coe[i] != 1.0)
if (coe[i] == -1.0)
std::cout << "-";
else
std::cout << coe[i];
if (i == 1)
std::cout << "x";
if (i>1)
std::cout << "x^" << i;
}
}
std::cout << std::endl;
}
int main()
{
std::vector< std::pair<double, double> > points1 = { {3,31}, {6,94}, {4,48}, {0,4} };
std::vector<double> coe = solveEq(points1);
printCoe(coe);
std::vector< std::pair<double, double> > points2 = { { 0,0 },{ 1,-1 },{ 2,-16 },{ 3,-81 },{ 4,-256 } };
printCoe(solveEq(points2));
printCoe(solveEq({ { 0,0 },{ 1,1 },{ 2,8 },{ 3,27 } }));
std::cin.ignore();
return 0;
}
Related
I'm trying to solve this problem using the slicing technic.
But I just passed the first two test cases in this gym (Problem A)
2017-2018 ACM-ICPC East Central North America Regional Contest (ECNA 2017)
The whole step in my code looks like this:
calculate the total area using vector cross when inputting the polygon information.
find all the endpoints and intersection points, and record x value of them.
for each slice (sort x list and for each interval) find the lines from every polygon which crosses this interval and store this smaller segment.
sort segments.
for each trapezoid or triangle, calculate the area if this area is covered by some polygon.
sum them all to find the cover area.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<typename T> using p = pair<T, T>;
template<typename T> using vec = vector<T>;
template<typename T> using deq = deque<T>;
// #define dbg
#define yccc ios_base::sync_with_stdio(false), cin.tie(0)
#define al(a) a.begin(),a.end()
#define F first
#define S second
#define eb emplace_back
const int INF = 0x3f3f3f3f;
const ll llINF = 1e18;
const int MOD = 1e9+7;
const double eps = 1e-9;
const double PI = acos(-1);
double fcmp(double a, double b = 0, double eps = 1e-9) {
if (fabs(a-b) < eps) return 0;
return a - b;
}
template<typename T1, typename T2>
istream& operator>>(istream& in, pair<T1, T2>& a) { in >> a.F >> a.S; return in; }
template<typename T1, typename T2>
ostream& operator<<(ostream& out, pair<T1, T2> a) { out << a.F << ' ' << a.S; return out; }
struct Point {
double x, y;
Point() {}
Point(double x, double y) : x(x), y(y) {}
Point operator+(const Point& src) {
return Point(src.x + x, src.y + y);
}
Point operator-(const Point& src) {
return Point(x - src.x, y - src.y);
}
Point operator*(double src) {
return Point(x * src, y * src);
}
//* vector cross.
double operator^(Point src) {
return x * src.y - y * src.x;
}
};
struct Line {
Point sp, ep;
Line() {}
Line(Point sp, Point ep) : sp(sp), ep(ep) {}
//* check if two segment intersect.
bool is_intersect(Line src) {
if (fcmp(ori(src.sp) * ori(src.ep)) < 0 and fcmp(src.ori(sp) * src.ori(ep)) < 0) {
double t = ((src.ep - src.sp) ^ (sp - src.sp)) / ((ep - sp) ^ (src.ep - src.sp));
return fcmp(t) >= 0 and fcmp(t, 1) <= 0;
}
return false;
}
//* if two segment intersect, find the intersection point.
Point intersect(Line src) {
double t = ((src.ep - src.sp) ^ (sp - src.sp)) / ((ep - sp) ^ (src.ep - src.sp));
return sp + (ep - sp) * t;
}
double ori(Point src) {
return (ep - sp) ^ (src - sp);
}
bool operator<(Line src) const {
if (fcmp(sp.y, src.sp.y) != 0)
return sp.y < src.sp.y;
return ep.y < src.ep.y;
}
};
int next(int i, int n) {
return (i + 1) % n;
}
int main()
{
yccc;
int n;
cin >> n;
//* the point list and the line list of polygons.
vec<vec<Point>> p_list(n);
vec<vec<Line>> l_list(n);
//* x's set for all endpoints and intersection points
vec<double> x_list;
//* initializing point list and line list
double total = 0, cover = 0;
for (int i = 0; i < n; i++) {
int m;
cin >> m;
p_list[i].resize(m);
for (auto &k : p_list[i]) {
cin >> k.x >> k.y;
x_list.eb(k.x);
}
l_list[i].resize(m);
for (int k = 0; k < m; k++) {
l_list[i][k].sp = p_list[i][k];
l_list[i][k].ep = p_list[i][next(k, m)];
}
//* calculate the polygon area.
double tmp = 0;
for (int k = 0; k < m; k++) {
tmp += l_list[i][k].sp.x * l_list[i][k].ep.y - l_list[i][k].sp.y * l_list[i][k].ep.x;
}
total += abs(tmp);
}
//* find all intersection points
for (int i = 0; i < n; i++)
for (int k = i+1; k < n; k++) {
for (auto li : l_list[i])
for (auto lk : l_list[k])
if (li.is_intersect(lk)) {
x_list.eb(li.intersect(lk).x);
}
}
sort(al(x_list));
auto same = [](double a, double b) -> bool {
return fcmp(a, b) == 0;
};
x_list.resize(unique(al(x_list), same) - x_list.begin());
//* for each slicing, calculate the cover area.
for (int i = 0; i < x_list.size() - 1; i++) {
vec<pair<Line, int>> seg;
for (int k = 0; k < n; k++) {
for (auto line : l_list[k]) {
//* check if line crosses this slicing
if (fcmp(x_list[i], min(line.sp.x, line.ep.x)) >= 0 and fcmp(max(line.sp.x, line.ep.x), x_list[i+1]) >= 0) {
Point sub = line.ep - line.sp;
double t_sp = (x_list[i] - line.sp.x) / sub.x, t_ep = (x_list[i+1] - line.sp.x) / sub.x;
seg.eb(Line(Point(x_list[i], line.sp.y + sub.y * t_sp), Point(x_list[i+1], line.sp.y + sub.y * t_ep)), k);
}
}
}
//* sort this slicing
sort(al(seg));
deq<bool> inside(n);
int count = 0;
Line prev;
// cout << x_list[i] << ' ' << x_list[i+1] << endl;
//* calculate cover area in this slicing.
for (int k = 0; k < seg.size(); k++) {
if (count)
cover += ((seg[k].F.sp.y - prev.sp.y) + (seg[k].F.ep.y - prev.ep.y)) * (x_list[i+1] - x_list[i]);
prev = seg[k].F;
// cout << seg[k].S << ": (" << seg[k].F.sp.x << ", " << seg[k].F.sp.y << "), (" << seg[k].F.ep.x << ", " << seg[k].F.ep.y << ")" << endl;
inside[k] = !inside[k];
count += (inside[k] ? 1 : -1);
}
}
//* answer
cout << total / 2 << ' ' << cover / 2;
}
I can't not figure out which part I made a mistake :(
Here is the question:
There is a house with a backyard which is square bounded by
coordinates (0,0) in the southwest to (1000,1000) in
the northeast. In this yard there are a number of water sprinklers
placed to keep the lawn soaked in the middle of the summer. However,
it might or might not be possible to cross the yard without getting
soaked and without leaving the yard?
Input The input starts with a line containing an integer 1≤n≤1000, the
number of water sprinklers. A line follows for each sprinkler,
containing three integers: the (x,y)(x,y) location of the sprinkler
(0≤x,y,≤10000) and its range r (1≤r≤1000). The sprinklers will soak
anybody passing strictly within the range of the sprinkler (i.e.,
within distance strictly less than r).
The house is located on the west side (x=0) and a path is needed to
the east side of the yard (x=1000).
Output If you can find a path through the yard, output four real
numbers, separated by spaces, rounded to two digits after the decimal
place. These should be the coordinates at which you may enter and
leave the yard, respectively. If you can enter and leave at several
places, give the results with the highest y. If there is no way to get
through the yard without getting soaked, print a line containing
“IMPOSSIBLE”.
Sample Input
3
500 500 499
0 0 999
1000 1000 200
Sample output
0.00 1000.00 1000.00 800.00
Here is my thought process:
Define circle objects with x,y,r and write a function to determine if a given point is wet or not(inside the circle or not) on the circumference is not wet btw.
class circle {
int h;
int k;
int r;
public:
circle();
circle(int h, int k, int r){
this->h = h;
this->k = k;
this->r = r;
};
bool iswet(pair<int,int>* p){
if (pow(this->r - 0.001, 2) > (pow(p->first - this->h, 2) +
pow(p->second - this->k, 2) ) ) {
return true;
}
else
return false;
};
Then implement a depth first search, prioritizing to go up and right whenever possible.
However since circles are not guaranteed to be pass on integer coordinates an the result is expected in floats with double precision (xxx.xx). So if we keep everything in integers the grid suddenly becomes 100,000 x 100,000 which is way too big. Also the time limit is 1 sec.
So I thought ok lets stick to 1000x1000 and work with floats instead. Loop over int coordinates and whenever I hit a sprinkle just snap in the perimeter of the circle since we are safe in the perimeter. But in that case could not figure out how DFS work.
Here is the latest trial
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <utility>
#include <unordered_set>
#include <iomanip>
using namespace std;
const int MAXY = 1e3;
const int MAXX = 1e3;
const int MINY = 0;
const int MINX = 0;
struct pair_hash {
inline std::size_t operator()(const std::pair<int,int> & v) const {
return v.first*31+v.second;
}
};
class circle {
int h;
int k;
int r;
public:
circle();
circle(int h, int k, int r){
this->h = h;
this->k = k;
this->r = r;
};
bool iswet(pair<float,float>* p){
if (pow(this->r - 0.001, 2) > (pow(p->first - this->h, 2) + pow(p->second - this->k, 2) ) ) {
this->closest_pair(p);
return true;
}
else
return false;
};
void closest_pair(pair<float,float>* p){
float vx = p->first - this->h;
float vy = p->second - this->k;
float magv = sqrt(vx * vx + vy * vy);
p->first = this->h + vx / magv * this->r;
p->second = this->k + vy / magv * this->r;
}
};
static bool test_sprinkles(vector<circle> &sprinkles, pair<float,float>* p){
for (int k = 0; k < sprinkles.size(); k++)
if (sprinkles[k].iswet(p)) return false;
return true;
}
int main(){
int n; // number of sprinkles
while (cin >> n){
vector<circle> sprinkles_array;
sprinkles_array.reserve(n);
int h, k, r;
while (n--){
cin >> h >> k >> r;
sprinkles_array.push_back(circle(h, k, r));
}/* code */
pair<float,float> enter = make_pair(0, MAXY);
deque<pair<float,float>> mystack;
mystack.push_back(enter);
pair<float,float>* cp;
bool found = false;
unordered_set<pair<float, float>, pair_hash> visited;
while (!mystack.empty()){
cp = &mystack.back();
if (cp->first == MAXX) {
found = true;
break;
}
visited.insert(*cp);
if (cp->second > MAXY || cp->second < MINY || cp ->first < MINX ) {
visited.insert(*cp);
mystack.pop_back();
continue;
}
if (!test_sprinkles(sprinkles_array,cp)) {
continue;
}
pair<int,int> newpair = make_pair(cp->first, cp->second + 1);
if (visited.find(newpair) == visited.end()) {
mystack.push_back(newpair);
continue;
}
else visited.insert(newpair);
newpair = make_pair(cp->first + 1 , cp->second);
if (visited.find(newpair) == visited.end()) {
mystack.push_back(newpair);
continue;
}
else visited.insert(newpair);
newpair = make_pair(cp->first, cp->second - 1);
if (visited.find(newpair) == visited.end()) {
mystack.push_back(newpair);
continue;
}
else visited.insert(newpair);
newpair = make_pair(cp->first - 1, cp->second);
if (visited.find(newpair) == visited.end()) {
mystack.push_back(newpair);
continue;
}
else visited.insert(newpair);
mystack.pop_back();
}
cout << setprecision(2);
cout << fixed;
if (found){
double xin = mystack.front().first;
double yin = mystack.front().second;
pair <float, float> p = mystack.back();
p.second++;
for (int k = 0; k < sprinkles_array.size(); k++)
if (sprinkles_array[k].iswet(&p)) break;
double xout = p.first;
double yout = p.second;
cout << xin << " " << yin << " " << xout << " " << yout << endl;
}
else
{
cout << "IMPOSSIBLE" << endl;
}
}
}
Yes #JosephIreland is right. Solved it with grouping intersecting (not touching) circles. Then these groups have maxy and min y coordinates. If it exceeds the yard miny and maxy the way is blocked.
Then these groups also have upper and lower intersection points with x=0 and x=1000 lines. If the upper points are larger than the yard maxy then the maximum entry/exit points are lower entery points.
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <utility>
#include <iomanip>
using namespace std;
const int MAXY = 1e3;
const int MAXX = 1e3;
const int MINY = 0;
const int MINX = 0;
struct circle {
int h;
int k;
int r;
float maxy;
float miny;
circle();
circle(int h, int k, int r){
this->h = h;
this->k = k;
this->r = r;
this->miny = this->k - r;
this->maxy = this->k + r;
};
};
struct group {
float maxy = -1;
float miny = -1;
vector<circle*> circles;
float upper_endy = -1;
float upper_starty = -1;
float lower_endy = -1;
float lower_starty = -1;
void add_circle(circle& c){
if ((c.maxy > this->maxy) || this->circles.empty() ) this->maxy = c.maxy;
if ((c.miny < this->miny) || this->circles.empty() ) this->miny = c.miny;
this->circles.push_back(&c);
// find where it crosses x=minx and x= maxx
float root = sqrt(pow(c.r, 2) - pow(MINX - c.h, 2));
float y1 = root + c.k;
float y2 = -root + c.k;
if (y1 > this->upper_starty) this->upper_starty = y1;
if (y2 > this->lower_starty) this->lower_starty = y2;
root = sqrt(pow(c.r, 2) - pow(MAXX - c.h, 2));
y1 = root + c.k;
y2 = -root + c.k;
if (y1 > this->upper_endy) this->upper_endy = y1;
if (y2 > this->lower_endy) this->lower_endy = y2;
};
bool does_intersect(circle& c1){
for(circle* c2 : circles){
float dist = sqrt(pow(c1.h - c2->h,2)) + sqrt(pow(c1.k - c2->k,2));
(dist < (c1.r + c2->r)) ? true : false;
};
};
};
int main(){
int n; // number of sprinkles
while (cin >> n){
vector<circle> sprinkles_array;
sprinkles_array.reserve(n);
int h, k, r;
while (n--){
cin >> h >> k >> r;
sprinkles_array.push_back(circle(h, k, r));
}/* code */
vector<group> groups;
group newgroup;
newgroup.add_circle(sprinkles_array[0]);
groups.push_back(newgroup);
for (int i = 1; i < sprinkles_array.size(); i++){
bool no_group = true;
for (group g:groups){
if (g.does_intersect(sprinkles_array[i])){
g.add_circle(sprinkles_array[i]);
no_group = false;
break;
}
}
if (no_group) {
group newgroup;
newgroup.add_circle(sprinkles_array[i]);
groups.push_back(newgroup);
}
}
float entery = MAXY;
float exity = MAXY;
bool found = true;
for (group g : groups){
if ((g.miny < MINY) && (g.maxy > MAXY)){
found = false;
break;
}
if (g.upper_starty > entery)
entery = g.lower_starty;
if (g.upper_endy > exity)
exity = g.lower_endy;
}
cout << setprecision(2);
cout << fixed;
if (found){
cout << float(MINX) << " " << entery << " " << float(MAXX) << " " << exity << endl;
}
else
{
cout << "IMPOSSIBLE" << endl;
}
}
}
EDITED
I am trying to calculate the exponent of a matrix or the e of a matrix. Using some expected results, e.g. for a simple complex number of 1 + I. I have implemented some changes to divide by n factorial. Still having a similar issue whereby after some iterations the values blow up like crazy.
Output
This program will calculat
> Blockquotee the exp of a matrix A
Calculating power of matrix
(1,1)(1,1)(1,1)
(1,1)(1,1)(1,1)
(1,1)(1,1)(1,1)
Performing scalar division
(1,1)(1,1)(1,1)
(1,1)(1,1)(1,1)
(1,1)(1,1)(1,1)
Performing Summation
(1,1)(1,1)(1,1)
(1,1)(1,1)(1,1)
(1,1)(1,1)(1,1)
1
Calculating power of matrix
(0,6)(0,6)(0,6)
(0,6)(0,6)(0,6)
(0,6)(0,6)(0,6)
Performing scalar division
(0,6)(0,6)(0,6)
(0,6)(0,6)(0,6)
(0,6)(0,6)(0,6)
Performing Summation
(1,7)(1,7)(1,7)
(1,7)(1,7)(1,7)
(1,7)(1,7)(1,7)
2
Calculating power of matrix
(-18,18)(-18,18)(-18,18)
(-18,18)(-18,18)(-18,18)
(-18,18)(-18,18)(-18,18)
Performing scalar division
(-18,18)(-18,18)(-18,18)
(-18,18)(-18,18)(-18,18)
(-18,18)(-18,18)(-18,18)
Performing Summation
(-17,25)(-17,25)(-17,25)
(-17,25)(-17,25)(-17,25)
(-17,25)(-17,25)(-17,25)
3
Calculating power of matrix
(-108,0)(-108,0)(-108,0)
(-108,0)(-108,0)(-108,0)
(-108,0)(-108,0)(-108,0)
Performing scalar division
(-108,0)(-108,0)(-108,0)
(-108,0)(-108,0)(-108,0)
(-108,0)(-108,0)(-108,0)
Performing Summation
(-125,25)(-125,25)(-125,25)
(-125,25)(-125,25)(-125,25)
(-125,25)(-125,25)(-125,25)
4
Calculating power of matrix
(-324,-324)(-324,-324)(-324,-324)
(-324,-324)(-324,-324)(-324,-324)
(-324,-324)(-324,-324)(-324,-324)
Performing scalar division
(-324,-324)(-324,-324)(-324,-324)
(-324,-324)(-324,-324)(-324,-324)
(-324,-324)(-324,-324)(-324,-324)
Performing Summation
(-449,-299)(-449,-299)(-449,-299)
(-449,-299)(-449,-299)(-449,-299)
(-449,-299)(-449,-299)(-449,-299)
5
Calculating power of matrix
(0,-1944)(0,-1944)(0,-1944)
(0,-1944)(0,-1944)(0,-1944)
(0,-1944)(0,-1944)(0,-1944)
Performing scalar division
(0,-1944)(0,-1944)(0,-1944)
(0,-1944)(0,-1944)(0,-1944)
(0,-1944)(0,-1944)(0,-1944)
Performing Summation
(-449,-2243)(-449,-2243)(-449,-2243)
(-449,-2243)(-449,-2243)(-449,-2243)
(-449,-2243)(-449,-2243)(-449,-2243)
6
Calculating power of matrix
(5832,-5832)(5832,-5832)(5832,-5832)
(5832,-5832)(5832,-5832)(5832,-5832)
(5832,-5832)(5832,-5832)(5832,-5832)
Performing scalar division
(5832,-5832)(5832,-5832)(5832,-5832)
(5832,-5832)(5832,-5832)(5832,-5832)
(5832,-5832)(5832,-5832)(5832,-5832)
Performing Summation
(5383,-8075)(5383,-8075)(5383,-8075)
(5383,-8075)(5383,-8075)(5383,-8075)
(5383,-8075)(5383,-8075)(5383,-8075)
7
Calculating power of matrix
(34992,0)(34992,0)(34992,0)
(34992,0)(34992,0)(34992,0)
(34992,0)(34992,0)(34992,0)
Performing scalar division
(34992,0)(34992,0)(34992,0)
(34992,0)(34992,0)(34992,0)
(34992,0)(34992,0)(34992,0)
Performing Summation
(40375,-8075)(40375,-8075)(40375,-8075)
(40375,-8075)(40375,-8075)(40375,-8075)
(40375,-8075)(40375,-8075)(40375,-8075)
8
Calculating power of matrix
(104976,104976)(104976,104976)(104976,104976)
(104976,104976)(104976,104976)(104976,104976)
(104976,104976)(104976,104976)(104976,104976)
Performing scalar division
(104976,104976)(104976,104976)(104976,104976)
(104976,104976)(104976,104976)(104976,104976)
(104976,104976)(104976,104976)(104976,104976)
Performing Summation
(145351,96901)(145351,96901)(145351,96901)
(145351,96901)(145351,96901)(145351,96901)
(145351,96901)(145351,96901)(145351,96901)
9
#pragma once
#include <iostream>
#include <complex>
#include <cmath>
#include <cassert>
using namespace std;
class ComplexMatrix
{
private:
complex<long double>** Arr;
int mi = 3;
int mj = 3;
public:
ComplexMatrix();
//~ComplexMatrix();
ComplexMatrix(int i, int j);
ComplexMatrix(const ComplexMatrix&);
void Initialise(complex<long double>);
void DisplayMatrix();
void DeleteMatrix();
void EnterComplexMatrix(int, int);
ComplexMatrix matrixPower(ComplexMatrix&, int);
ComplexMatrix ScalarDivision_Fac(ComplexMatrix& , complex<long
double>);
ComplexMatrix MatrixAddition(ComplexMatrix&, ComplexMatrix&);
ComplexMatrix matrixSq(ComplexMatrix&);
ComplexMatrix Multiply(ComplexMatrix, ComplexMatrix);
ComplexMatrix matrixe_A(ComplexMatrix&, int);
ComplexMatrix operator*(const ComplexMatrix&);
ComplexMatrix operator=(const ComplexMatrix&);
friend ComplexMatrix operator+(const ComplexMatrix&, const ComplexMatrix&);
};
//Constructor to initialise a default 3 x 3 complex matrix with 0s for real and imaginary values
ComplexMatrix::ComplexMatrix()
{
Arr = new complex<long double> * [mi];
for (int x = 0; x < mi; x++)
{
Arr[x] = new complex<long double> [mj];
}
for (int x1 = 0; x1 < mi; x1++)
{
for (int y1 = 0; y1 < mj; y1++)
{
Arr[x1][y1] = (0.0, 0.0);
}
}
}
//Constructor to initialise a user defined complex matrix of a particular size with 0s for real
and imaginary values
ComplexMatrix::ComplexMatrix(int i, int j)
{
mi = i;
mj = j;
Arr = new complex<long double> * [i];
for (int x = 0; x < i; x++)
{
Arr[x] = new complex<long double>[j];
}
for (int x1 = 0; x1 < i; x1++)
{
for (int y1 = 0; y1 < j; y1++)
{
Arr[x1][y1] = (0.0, 0.0);
}
}
}
//Copy Constructor
ComplexMatrix::ComplexMatrix(const ComplexMatrix& CM)
//lets only have ARR mean one thing to make it easier to read, understand,
and to avoid this->
clutter.
{
Arr = new complex<long double> * [mi];
for (int x = 0; x < mi; x++)
{
Arr[x] = new complex<long double>[mj];
}
for (int x1 = 0; x1 < mi; x1++)
{
for (int y1 = 0; y1 < mj; y1++)
{
Arr[x1][y1] = CM.Arr[x1][y1];
}
}
}
/*
ComplexMatrix::~ComplexMatrix()
{
for (int x = 0; x < mi; x++)
{
delete[] Arr[x];
}
delete[] Arr;
}
*/
//Initialise matrix elements to a particular value
void ComplexMatrix::Initialise(complex<long double> x)
{
for (int i = 0; i < mi; i++)
{
for (int j = 0; j < mj; j++)
{
Arr[i][j] = x;
}
}
}
//Display the matrix member function
void ComplexMatrix::DisplayMatrix()
{
for (int x = 0; x < mi; x++)
{
for (int y = 0; y < mj; y++)
{
cout << Arr[x][y];
}
cout << endl;
}
}
//Delete the memory allocated by the matrix member function
void ComplexMatrix::DeleteMatrix()
{
for (int x = 0; x < mi; x++)
{
delete[] Arr[x];
}
delete[] Arr;
}
//Enter complex matrix elements member function
void ComplexMatrix::EnterComplexMatrix(int i, int j)
{
double real, img;
complex < long double> temp = (0.0, 0.0);
cout << "Your matrix will have " << i * j << " elements" << endl;
//Prompt for user input and assign values for real and imaginary values
for (int x = 0; x < i; x++)
{
for (int y = 0; y < j; y++)
{
cout << "Enter the details for the real part of element" << "[" <<
x << "]" << "[" << y
<< "]" << endl;
cin >> real;
cout << "Enter the details for the real part of element" << "[" <<
x << "]" << "[" << y
<< "]" << endl;
cin >> img;
temp = (real, img);
Arr[x][y] = temp;
}
}
}
ComplexMatrix ComplexMatrix::Multiply(ComplexMatrix x, ComplexMatrix y)
{
ComplexMatrix z(3, 3);
for (int x1 = 0; x1 < 3; ++x1)
{
for (int y1 = 0; y1 < 3; ++y1)
{
for (int z1 = 0; z1 < 3; ++z1)
{
Arr[x1][y1] += x.Arr[x1][z1] * y.Arr[z1][y1];
}
}
}
return z;
}
ComplexMatrix ComplexMatrix::ScalarDivision_Fac(ComplexMatrix& x,
complex<long double> n)
{
ComplexMatrix newCompArr(3, 3);
complex <long double> fac = 0.0;
int n1 = static_cast <int>(n.real());
n1 = static_cast <int>(n1);
complex <long double> i1;
for (int i = 1; i < n1; i++)
{
i1 = i;
fac = fac * i1;
}
for (int x1 = 0; x1 < mi; x1++)
{
for (int y1 = 0; y1 < mj; y1++)
{
newCompArr.Arr[x1][y1] = x.Arr[x1][y1] / fac;
}
}
return newCompArr;
}
ComplexMatrix ComplexMatrix::matrixSq(ComplexMatrix& x)
{
ComplexMatrix result(mi, mj);
result = x * x;
return result;
}
ComplexMatrix ComplexMatrix::matrixPower(ComplexMatrix& a, int n)
{
ComplexMatrix result(mi, mj);
ComplexMatrix temp(mi, mj);
temp = a;
if (n % 2 == 0)
{
for (int i = 1; i < n / 2; i++)
{
result = temp * a;
temp = result;
}
result = temp;
result = result.matrixSq(result);
}
else
{
for (int j = 0; j < (n - 1) ; j++)
{
result = temp * a;
temp = result;
}
result = temp;
}
return result;
}
ComplexMatrix ComplexMatrix::matrixe_A(ComplexMatrix& A, int n)
{
ComplexMatrix expA(mi, mj);
ComplexMatrix sum(mi, mj);
sum.Initialise({ 0.0, 0.0 });
ComplexMatrix A_n(mi, mj);
ComplexMatrix A_n_div_n(mi, mj);
ComplexMatrix temp(mi, mj);
ComplexMatrix zero(mi, mj);
zero.Initialise({ 0.0, 0.0 });
complex <long double> j;
for (int i = 1; i < n; i++)
{
cout << "Calculating power of matrix" << endl;
A_n = A.matrixPower(A, i);
A_n.DisplayMatrix();
A_n_div_n = A_n;
cout << "Performing scalar division" << endl;
A_n_div_n.ScalarDivision(A_n_div_n, i);
A_n_div_n.DisplayMatrix();
cout << endl;
temp = zero;
temp = A_n_div_n;
cout << "Performing Summation" << endl;
sum = sum + temp;
sum.DisplayMatrix();
cout << i << endl;
cout << endl;
temp = zero;
A_n = A.matrixPower(A, i);
}
return sum;
}
ComplexMatrix ComplexMatrix::operator*(const ComplexMatrix& CompArr)
{
ComplexMatrix newCompArr(3, 3);
for (int x1 = 0; x1 < 3; ++x1)
{
for (int y1 = 0; y1 < 3; ++y1)
{
newCompArr.Arr[x1][y1] = {0.0, 0.0};
for (int z1 = 0; z1 < 3; ++z1)
{
newCompArr.Arr[x1][y1] += Arr[x1][z1] * CompArr.Arr[z1][y1];
}
}
}
return newCompArr;
}
ComplexMatrix ComplexMatrix::operator=(const ComplexMatrix& CM)
{
mi = 3;
mj = 3;
//ComplexMatrix Arr(3, 3);
for (int x1 = 0; x1 < mi; x1++)
{
for (int y1 = 0; y1 < mj; y1++)
{
Arr[x1][y1] = CM.Arr[x1][y1];
}
}
//return Arr;
return *this;
}
ComplexMatrix operator+(const ComplexMatrix &x, const ComplexMatrix &y)
{
int mi = 3;
int mj = 3;
ComplexMatrix newCompArr(3, 3);
for (int x1 = 0; x1 < mi; x1++)
{
for (int y1 = 0; y1 < mj; y1++)
{
newCompArr.Arr[x1][y1] = { (x.Arr[x1][y1].real() + y.Arr[x1][y1].real()) ,
(x.Arr[x1][y1].imag() + y.Arr[x1][y1].imag()) };
}
}
return newCompArr;
}
#include <iostream>
#include "Header.h"
#include <complex>
#include <cmath>
using namespace std;
int main()
{
std::cout << "This program will calculate the exp of a matrix A\n";
complex<long double> x = {1, 1};
complex<long double> y = {2, 2};
complex<long double> z = { 0.0, 0.0 };
ComplexMatrix z1(3, 3);
ComplexMatrix z2(3, 3);
ComplexMatrix z3(3, 3);
z2.Initialise(x);
z3 = z2.matrixe_A(z2, 10);
//z3.DisplayMatrix();
z1.DeleteMatrix();
z2.DeleteMatrix();
}
I'm trying to implement a gradient descent algorithm in C++. Here's the code I have so far :
#include <iostream>
double X[] {163,169,158,158,161,172,156,161,154,145};
double Y[] {52, 68, 49, 73, 71, 99, 50, 82, 56, 46 };
double m, p;
int n = sizeof(X)/sizeof(X[0]);
int main(void) {
double alpha = 0.00004; // 0.00007;
m = (Y[1] - Y[0]) / (X[1] - X[0]);
p = Y[0] - m * X[0];
for (int i = 1; i <= 8; i++) {
gradientStep(alpha);
}
return 0;
}
double Loss_function(void) {
double res = 0;
double tmp;
for (int i = 0; i < n; i++) {
tmp = Y[i] - m * X[i] - p;
res += tmp * tmp;
}
return res / 2.0 / (double)n;
}
void gradientStep(double alpha) {
double pg = 0, mg = 0;
for (int i = 0; i < n; i++) {
pg += Y[i] - m * X[i] - p;
mg += X[i] * (Y[i] - m * X[i] - p);
}
p += alpha * pg / n;
m += alpha * mg / n;
}
This code converges towards m = 2.79822, p = -382.666, and an error of 102.88. But if I use my calculator to find out the correct linear regression model, I find that the correct values of m and p should respectively be 1.601 and -191.1.
I also noticed that the algorithm won't converge for alpha > 0.00007, which seems quite low, and the value of p barely changes during the 8 iterations (or even after 2000 iterations).
What's wrong with my code?
Here's a good overview of the algorithm I'm trying to implement. The values of theta0 and theta1 are called p and m in my program.
Other implementation in python
More about the algorithm
This link gives a comprehensive view of the algorithm; it turns out I was following a completely wrong approach.
The following code does not work properly (and I have no plans to work on it further), but should put on track anyone who's confronted to the same problem as me :
#include <vector>
#include <iostream>
typedef std::vector<double> vect;
std::vector<double> y, omega(2, 0), omega2(2, 0);;
std::vector<std::vector<double>> X;
int n = 10;
int main(void) {
/* Initialize x so that each members contains (1, x_i) */
/* Initialize x so that each members contains y_i */
double alpha = 0.00001;
display();
for (int i = 1; i <= 8; i++) {
gradientStep(alpha);
display();
}
return 0;
}
double f_function(const std::vector<double> &x) {
double c;
for (unsigned int i = 0; i < omega.size(); i++) {
c += omega[i] * x[i];
}
return c;
}
void gradientStep(double alpha) {
for (int i = 0; i < n; i++) {
for (unsigned int j = 0; j < X[0].size(); j++) {
omega2[j] -= alpha/(double)n * (f_function(X[i]) - y[i]) * X[i][j];
}
}
omega = omega2;
}
void display(void) {
double res = 0, tmp = 0;
for (int i = 0; i < n; i++) {
tmp = y[i] - f_function(X[i]);
res += tmp * tmp; // Loss functionn
}
std::cout << "omega = ";
for (unsigned int i = 0; i < omega.size(); i++) {
std::cout << "[" << omega[i] << "] ";
}
std::cout << "\tError : " << res * .5/(double)n << std::endl;
}
I was asked this Interview Question (C++,algos)and had no idea how to solve it.
Given an array say Arr[N] containing Cartesian coordinates of N distinct points count the number of triples (Arr[P], Arr[Q], Arr[R]) such that P < Q < R < N and the points Arr[P], Arr[Q], Arr[R] are collinear (i.e lie on the same straight line).
Any ideas? What algorithm can I use for this?
The following is probably not optimized, but its complexity is the one your interviewer requested.
First create a list of (a,b,c) values for each couple of points (N² complexity)
--> (a,b,c) stands for the cartesian equation of a straight line a*x+b*y+c=0
Given two points and their coordinates (xa, ya) and (xb, yb), computing (a,b,c) is simple.
Either you can find a solution to
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
or to
xa = gamma*ya+delta
xb = gamma*yb+delta
(you get the point)
The solvable set of equations can then be rewritten in the more general form
a*x+b*y+c = 0
Then sort the list (N² log(N²) complexity therefore N²log(N) complexity).
Iterate over elements of the list. If two sequential elements are equal, corresponding points are collinear. N² complexity.
You might want to add a last operation to filter duplicate results, but you should be fine, complexity-wise.
EDIT : i updated a bit the algorithm while coding it to make it more simple and optimal. Here it goes.
#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;
}
For the count of Collinear triplets, identify a line with any two points and then check whether a new line formed by any other two points might be coinciding or parallel and that needs to be taken care of while computing the collinear triplets.
To solve:
First, collect all points on a line using Map<Line, Set<Point2d>>
as suggested in the question itself.
For triplets filter out those lines which have at least three points
Then compute nC3 for each of those add to global result.
Code for the above problem below
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);
}
}
}
The time complexity for above code O(N^2) and space complexity is O(N)
If it's 2 dimension points: 3 points (P,Q,R) are collinear if (P,Q), (P,R) define the same slope.
m = (p.x - q.x) / (p.y - q.y) ; slope
Somehow you need to check all possible combinations and check, an efficient algo is trick as the first naive is N*(N-1)*(N-2)...
Instead of 3 loops, whish is O(n³), precompute the slopes of all lines given by two points Arr[P], Arr[Q]. That's O(n²). Then compare these slopes.
You can improve that further sorting the lines by their slope during computation or afterwards, which is O(n log n). After that finding lines with the same slope is O(n).
But you may have to pay a price for that by implementing a data structure, when you want to know, which points are collinear.
I think the key point of an interview question is not to give the perfect algorithm, but to identify and discuss the problems within an idea.
Edit:
Brute force approach:
#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;
}
It's trivial to see that you can get all the pairs of points and their slope & y-intercepts in O(n^2) time. So the output is:
IndexB Slope Y-Intercept IndexA
Of course, we won't insert any entries where IndexA = IndexB.
Let's have this table indexed on (IndexB,Slope,Y), which forces our insert into this table as O(log(n))
After we fill out this table with new records (B',S',Y',A'), we check to see if we already have an element such that B'=A of the existing table and B!=A' of the new record (meaning we have a unique triplet) that matches the slope and Y-intercept (meaning collinear). If this is the case and A < B < B', increment the count by 1.
EDIT: One clarifying remark. We need to make sure that we fill this table "backwards" first, taking all the pairs that wouldn't satisfy A < B (< C). This ensures that they will exist in the table before we start testing for their existence.
EDIT: Wow my C++ is rusty... took a while.
#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;
}
I have this solution tell if there is a better one,
Sort all the points according to the slope they make with the x axis or any other axis you want ( O(n* logn) ). Now all you have to do if go through the sorted list and find points which have same slope either inpositive or negative direction( this can be done in linear time i.e. O(n) ) . Lets say you get m such points for one case then increment the answer by C(m,3)..
Total time depends on how good you implement C(m,3)
But asymptotically O(N logN)
Edit: After seeing icCube's comment i realize that we cannot take any axis..so for the above defined algo taking the slope calculating point as one of the n points ( thus n times ) should be my best guess. But it makes the algorithm N*N*Log(N)