logo

Găsirea numărului de triunghiuri dintre segmentele de linii orizontale și verticale

Cerințe preliminare: PIC  Având în vedere „n” segmente de linie, fiecare dintre ele este orizontal sau vertical, găsiți numărul maxim de triunghiuri (inclusiv triunghiuri cu zonă zero) care pot fi formate prin unirea punctelor de intersecție ale segmentelor de dreaptă. Nu se suprapun două segmente orizontale și nici două segmente verticale. O linie este reprezentată folosind două puncte (patru numere întregi primele două fiind coordonatele x și y, respectiv, pentru primul punct și celelalte două fiind coordonatele x și y pentru al doilea punct) Exemple:

 | ---|-------|-- | | ----- | --|--|- | | | | For the above line segments there are four points of intersection between vertical and horizontal lines every three out of which form a triangle so there can be   4C3   triangles.

Ideea se bazează pe Algoritmul de baleiaj . Construirea unei soluții în pași:



  1. Stocați ambele puncte ale tuturor segmentelor de linie cu evenimentul corespunzător (descris mai jos) într-un vector și sortați toate punctele în ordinea nedescrescătoare a coordonatelor lor x.
  2. Să ne imaginăm acum o linie verticală pe care o parcurgem peste toate aceste puncte și să descriem 3 evenimente în funcție de punctul în care ne aflăm în prezent:
      în- punctul cel mai din stânga al unui segment de linie orizontalăafară- punctul cel mai din dreapta al unui segment de linie orizontală
    • o linie verticală
  3. Numim regiunea 'activ' sau liniile orizontale 'activ' care au avut primul eveniment, dar nu al doilea. Vom avea un BIT (arborele indexat binar) pentru a stoca coordonatele „y” ale tuturor liniilor active.
  4. Odată ce o linie devine inactivă, îi eliminăm „y”-ul din BIT.
  5. Când are loc un eveniment de al treilea tip, atunci când ne aflăm la o linie verticală, interogăm arborele în intervalul coordonatelor sale „y” și adăugăm rezultatul la numărul de puncte de intersecție de până acum.
  6. În cele din urmă vom avea numărul de puncte de intersecții să spunem m atunci numărul de triunghiuri (inclusiv zona zero) va fi mC3 .

Nota: Trebuie să sortăm cu atenție punctele, uită-te la cmp() funcţionează în implementare pentru clarificare. 

CPP
// A C++ implementation of the above idea #include   #define maxy 1000005 #define maxn 10005 using namespace std; // structure to store point struct point {  int x y;  point(int a int b)  {  x = a y = b;  } }; // Note: Global arrays are initially zero // array to store BIT and vector to store // the points and their corresponding event number // in the second field of the pair int bit[maxy]; vector<pair<point int> > events; // compare function to sort in order of non-decreasing // x coordinate and if x coordinates are same then // order on the basis of events on the points bool cmp(pair<point int> &a pair<point int> &b) {  if ( a.first.x != b.first.x )  return a.first.x < b.first.x;  //if the x coordinates are same  else  {  // both points are of the same vertical line  if (a.second == 3 && b.second == 3)  {  return true;  }  // if an 'in' event occurs before 'vertical'  // line event for the same x coordinate  else if (a.second == 1 && b.second == 3)  {  return true;  }  // if a 'vertical' line comes before an 'in'  // event for the same x coordinate swap them  else if (a.second == 3 && b.second == 1)  {  return false;  }  // if an 'out' event occurs before a 'vertical'  // line event for the same x coordinate swap.  else if (a.second == 2 && b.second == 3)  {  return false;  }  //in all other situations  return true;  } } // update(y 1) inserts a horizontal line at y coordinate // in an active region while update(y -1) removes it void update(int idx int val) {  while (idx < maxn)  {  bit[idx] += val;  idx += idx & (-idx);  } } // returns the number of lines in active region whose y // coordinate is between 1 and idx int query(int idx) {  int res = 0;  while (idx > 0)  {  res += bit[idx];  idx -= idx & (-idx);  }  return res; } // inserts a line segment void insertLine(point a point b) {  // if it is a horizontal line  if (a.y == b.y)  {  int beg = min(a.x b.x);  int end = max(a.x b.x);  // the second field in the pair is the event number  events.push_back(make_pair(point(beg a.y) 1));  events.push_back(make_pair(point(end a.y) 2));  }  //if it is a vertical line  else  {  int up = max(b.y a.y);  int low = min(b.y a.y);  //the second field of the pair is the event number  events.push_back(make_pair(point(a.x up) 3));  events.push_back(make_pair(point(a.x low) 3));  } } // returns the number of intersection points between all // the lines vertical and horizontal to be run after the // points have been sorted using the cmp() function int findIntersectionPoints() {  int intersection_pts = 0;  for (int i = 0 ; i < events.size() ; i++)  {  //if the current point is on an 'in' event  if (events[i].second == 1)  {  //insert the 'y' coordinate in the active region  update(events[i].first.y 1);  }  // if current point is on an 'out' event  else if (events[i].second == 2)  {  // remove the 'y' coordinate from the active region  update(events[i].first.y -1);  }  // if the current point is on a 'vertical' line  else  {  // find the range to be queried  int low = events[i++].first.y;  int up = events[i].first.y;  intersection_pts += query(up) - query(low);  }  }  return intersection_pts; } // returns (intersection_pts)C3 int findNumberOfTriangles() {  int pts = findIntersectionPoints();  if ( pts >= 3 )  return ( pts * (pts - 1) * (pts - 2) ) / 6;  else  return 0; } // driver code int main() {  insertLine(point(2 1) point(2 9));  insertLine(point(1 7) point(6 7));  insertLine(point(5 2) point(5 8));  insertLine(point(3 4) point(6 4));  insertLine(point(4 3) point(4 5));  insertLine(point(7 6) point(9 6));  insertLine(point(8 2) point(8 5));  // sort the points based on x coordinate  // and event they are on  sort(events.begin() events.end() cmp);  cout << "Number of triangles are: " <<  findNumberOfTriangles() << "n";  return 0; } 

Ieșire:

Number of triangles are: 4
Time Complexity:   O( n * log(n) + n * log(maximum_y) )  

Spațiu auxiliar: O(maxy) unde maxy = 1000005