一切看起來除了getLargestRect()
,而你也過於複雜不錯。只需返回rectangle(minX, minY, maxX, maxY)
即可。您可以在線性時間內找到分鐘數和最大值。當所有行具有相同的長度時,當前實現是O(n )。
我也編寫了我自己的算法,如果你想看看不同的方法。我的想法是將所有垂直線存儲在一個奇特的數據結構中,然後掃描水平線並找到它們關閉的矩形。
當查看水平線h
時,所有具有y1 < h.y && y2 >= h.y
的垂直線都按照它們的x值存儲在地圖中。當前水平線形成包含從map[h.x1]
到map[h.x2]
的所有垂直線的矩形。外部兩行延伸過h.y
,但所有中間行必須在h.y
處結束,因此在計算矩形區域後將其從地圖中移除。根據它們的y1
值,通過對垂直線進行排序,可以高效地找到需要爲每條水平線添加到地圖上的垂直線。
下面是代碼:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) < (b) ? (b) : (a))
using namespace std;
class Horizontal
{
public:
int x1, x2, y;
Horizontal(int x1, int x2, int y) : x1(x1), x2(x2), y(y) {}
static bool comp(const Horizontal & a, const Horizontal & b)
{
return a.y < b.y;
}
};
class Vertical
{
public:
int x, y1; // no need to store y2
Vertical(int x, int y1) : x(x), y1(y1) {}
static bool comp(const Vertical & a, const Vertical & b)
{
return a.y1 < b.y1;
}
};
long long total = 0;
int vertI = 0; // index of next vertical to add to currentVerts
map<int, int> currentVerts; // currentVerts[5] = y1 of the vert line with x=5
vector<Vertical> verticals;
vector<Horizontal> horizontals;
vector<int> solutions;
void readInput();
void processHorizontal(Horizontal & line);
int main()
{
cout.precision(10);
readInput();
sort(verticals.begin(), verticals.end(), Vertical::comp);
sort(horizontals.begin(), horizontals.end(), Horizontal::comp);
// process the lines (start at i = 1 to ignore the top one)
for (int i = 1; i < horizontals.size(); i++)
{
processHorizontal(horizontals[i]);
}
sort(solutions.begin(), solutions.end());
for (int i = solutions.size() - 1; i >= 0; i--)
{
cout << (double) solutions[i]/total << "\n";
}
}
void readInput()
{
int n;
cin >> n;
int x1, x2, y1, y2;
for (int i = 0; i < n; i++)
{
cin >> x1 >> y1 >> x2 >> y2;
if (x2 < x1) swap(x1, x2);
if (y2 < y1) swap(y1, y2);
if (x1 == x2) verticals.push_back(Vertical(x1, y1));
else horizontals.push_back(Horizontal(x1, x2, y1));
}
}
void processHorizontal(Horizontal & horiz)
{
// add all vert lines which start above horiz to currentVert
for (; vertI < verticals.size() && verticals[vertI].y1 < horiz.y;
vertI++)
{
int x = verticals[vertI].x;
currentVerts[x] = verticals[vertI].y1;
}
map<int, int>::iterator left = currentVerts.find(horiz.x1);
map<int, int>::iterator right = currentVerts.find(horiz.x2);
map<int, int>::iterator i;
map<int, int>::iterator next;
for (i = next = left; i != right; i = next)
{
next++;
int width = (*next).first - (*i).first; // difference in x
int height = horiz.y - (*i).second; // difference y
int area = width * height;
total += area;
solutions.push_back(area);
if (i != left)
{
// if i is not the start it must be a short
// line which ends here, so delete it
currentVerts.erase(i);
}
else
{
// if it is left, cut the rectangle at horiz.y
// by modifying the start of the line
(*i).second = horiz.y;
}
}
}
一個有趣的問題確實。我猜他們沒有提供更大的數據集? – kkm 2012-02-18 13:04:37