logo

Trobar el nombre de triangles entre segments de recta horitzontals i verticals

Requisits previs: BIT  Donats 'n' segments de línia, cadascun d'ells és horitzontal o vertical, trobeu el nombre màxim de triangles (inclosos triangles amb àrea zero) que es poden formar unint els punts d'intersecció dels segments de línia. No hi ha dos segments de línia horitzontals que es superposen ni dos segments de línia verticals. Una línia es representa mitjançant dos punts (quatre nombres enters primers dos són les coordenades x i y respectivament per al primer punt i els altres dos són les coordenades x i y per al segon punt) Exemples:

 | ---|-------|-- | | ----- | --|--|- | | | | 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.

La idea es basa en Algorisme de línia d'escombrat . Construir una solució en passos:



  1. Emmagatzema els dos punts de tots els segments de línia amb l'esdeveniment corresponent (descrit a continuació) en un vector i ordena tots els punts en ordre no decreixent de les seves coordenades x.
  2. Imaginem ara una línia vertical que escombrarem per tots aquests punts i descrivim 3 esdeveniments en funció del punt en què ens trobem actualment:
      en- punt més esquerre d'un segment de línia horitzontalfora- punt més a la dreta d'un segment de línia horitzontal
    • a línia vertical
  3. Anomenem la regió 'actiu' o les línies horitzontals 'actiu' que han tingut el primer esdeveniment però no el segon. Tindrem un BIT (arbre indexat binari) per emmagatzemar les coordenades 'y' de totes les línies actives.
  4. Un cop una línia esdevé inactiva, eliminem la seva "y" del BIT.
  5. Quan es produeix un esdeveniment de tercer tipus és quan ens trobem en una línia vertical consultem l'arbre en el rang de les seves coordenades 'y' i afegim el resultat al nombre de punts d'intersecció fins ara.
  6. Finalment tindrem el nombre de punts d'intersecció dir m llavors el nombre de triangles (inclosa l'àrea zero) serà mC3 .

Nota: Hem d'ordenar amb cura els punts mirant cmp() funció en la implementació per a l'aclariment. 

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

Sortida:

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

Espai auxiliar: O(maxy) on maxy = 1000005