Voraussetzungen: BISSCHEN Bei gegebenen „n“ Liniensegmenten, von denen jedes entweder horizontal oder vertikal ist, ermitteln Sie die maximale Anzahl von Dreiecken (einschließlich Dreiecken mit der Fläche Null), die durch Verbinden der Schnittpunkte der Liniensegmente gebildet werden können. Es überlappen sich weder zwei horizontale Liniensegmente noch zwei vertikale Liniensegmente. Eine Linie wird durch zwei Punkte dargestellt (vier ganze Zahlen, die ersten beiden sind die x- bzw. y-Koordinaten für den ersten Punkt und die anderen beiden sind die x- bzw. y-Koordinaten für den zweiten Punkt). Beispiele:
| ---|-------|-- | | ----- | --|--|- | | | | 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.
Die Idee basiert auf Sweep-Line-Algorithmus . Schrittweise Erstellung einer Lösung:
- Speichern Sie beide Punkte aller Liniensegmente mit dem entsprechenden Ereignis (unten beschrieben) in einem Vektor und sortieren Sie alle Punkte in nicht absteigender Reihenfolge ihrer x-Koordinaten.
- Stellen wir uns nun eine vertikale Linie vor, die wir über alle diese Punkte ziehen, und beschreiben drei Ereignisse basierend darauf, an welchem Punkt wir uns gerade befinden:
- A vertikale Linie
- Wir nennen die Region 'aktiv' oder die horizontalen Linien 'aktiv' die die erste Veranstaltung hatten, aber nicht die zweite. Wir werden einen BIT (Binary Indexed Tree) haben, um die Y-Koordinaten aller aktiven Linien zu speichern.
- Sobald eine Leitung inaktiv wird, entfernen wir ihr „y“ aus dem BIT.
- Wenn ein Ereignis der dritten Art auftritt, also wenn wir uns an einer vertikalen Linie befinden, fragen wir den Baum im Bereich seiner „y“-Koordinaten ab und addieren das Ergebnis zur Anzahl der bisherigen Schnittpunkte.
- Schließlich wollen wir noch die Anzahl der Schnittpunkte angeben M dann beträgt die Anzahl der Dreiecke (einschließlich der Nullfläche). MC3 .
In - Punkt ganz links auf einem horizontalen Liniensegmentaus - Punkt ganz rechts eines horizontalen LiniensegmentsNotiz: Wir müssen die Punkte sorgfältig sortieren cmp() Funktion in der Umsetzung zur Verdeutlichung.
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; } Ausgabe:
Number of triangles are: 4
Time Complexity: O( n * log(n) + n * log(maximum_y) )
Hilfsraum: O(maxy), wobei maxy = 1000005