# 題目: UVa 1206 - Boundary Points
# 題目說明
給數個點 (x, y 平面座標),求這些點的 凸包(Convex Hull)
INPUT:
每筆測資輸入一行,輸入表示為 (x,y)
,代表一個點的平面座標
OUTPUT:
輸出組成 凸包(Convex Hull)
的點的座標
# 解題方法
如果使用 Graham's Scan
演算法需要做極角排序
使用 Andrew's Monotone Chain
演算法則跑兩次半邊,將所有點覆蓋
直接讀入座標後跑 Andrew's Monotone Chain
即可
# 參考程式碼 Graham's Scan
#include <iostream> | |
#include <string> | |
#include <vector> | |
#include <sstream> | |
#include <algorithm> | |
#include <math.h> | |
using namespace std; | |
static auto fast_io = [] | |
{ | |
ios::sync_with_stdio(false); | |
cout.tie(nullptr); | |
cin.tie(nullptr); | |
return 0; | |
}(); | |
struct point | |
{ | |
double x; | |
double y; | |
double d; | |
}; | |
vector< point > V; | |
vector< point > ret; | |
string str; | |
double dist(point& a, point& b) | |
{ | |
return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2)); | |
} | |
double cross(point& o, point& a, point& b) | |
{ | |
return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); | |
} | |
bool cmp(point& a, point& b) | |
{ | |
auto c = cross(V[0], a, b); | |
return c == 0 ? a.d < b.d : c > 0; | |
} | |
void init() | |
{ | |
V.clear(); | |
ret.clear(); | |
} | |
void read() | |
{ | |
char _; | |
double a, b; | |
stringstream ss(str); | |
while (ss >> _ >> a >> _ >> b >> _) V.push_back({ a, b }); | |
} | |
void GrahamScan() | |
{ | |
sort(V.begin(), V.end(), [](point& a, point& b) | |
{ return a.y < b.y || (a.y == b.y && a.x < b.x); }); | |
for (int i = 1; i < V.size(); ++i) V[i].d = dist(V[0], V[i]); | |
sort(V.begin() + 1, V.end(), cmp); | |
V.emplace_back(V[0]); | |
for (int i = 0; i < V.size(); ++i) | |
{ | |
int m = ret.size(); | |
while (m >= 2 && cross(ret[m - 2], ret[m - 1], V[i]) <= 0) | |
{ | |
ret.pop_back(); | |
--m; | |
} | |
ret.emplace_back(V[i]); | |
} | |
} | |
void print() | |
{ | |
int S = ret.size(); | |
for (auto& [x, y, d] : ret) | |
{ | |
cout << '(' << x << ',' << y << ')'; | |
if (--S) cout << ' '; | |
} | |
cout << "\n"; | |
} | |
int main() | |
{ | |
while (getline(cin, str)) | |
{ | |
init(); | |
read(); | |
GrahamScan(); | |
print(); | |
} | |
} |
# 參考程式碼 Andrew's Monotone Chain
#include <iostream> | |
#include <string> | |
#include <sstream> | |
#include <vector> | |
#include <algorithm> | |
using namespace std; | |
struct point | |
{ | |
double x; | |
double y; | |
}; | |
string str; | |
vector<point> V; | |
vector<point> ret; | |
void init() | |
{ | |
V.clear(); | |
ret.clear(); | |
} | |
void read() | |
{ | |
char _; | |
double a, b; | |
stringstream ss(str); | |
while (ss >> _ >> a >> _ >> b >> _) V.push_back({ a, b }); | |
} | |
double cross(point& o, point& a, point& b) | |
{ | |
return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); | |
} | |
void Andrews_Monotone_Chain() | |
{ | |
sort(V.begin(), V.end(), [](point& a, point& b) | |
{ return a.y < b.y || (a.y == b.y && a.x < b.x); }); | |
for (int i = 0; i < V.size(); ++i) | |
{ | |
int m = ret.size(); | |
while (m >= 2 && cross(ret[m - 2], ret[m - 1], V[i]) <= 0) | |
{ | |
ret.pop_back(); | |
--m; | |
} | |
ret.emplace_back(V[i]); | |
} | |
for (int i = V.size() - 2, t = ret.size() + 1; i >= 0; --i) | |
{ | |
int m = ret.size(); | |
while (m >= t && cross(ret[m - 2], ret[m - 1], V[i]) <= 0) | |
{ | |
ret.pop_back(); | |
--m; | |
} | |
ret.emplace_back(V[i]); | |
} | |
} | |
void print() | |
{ | |
int S = ret.size(); | |
for (auto& [x, y] : ret) | |
{ | |
cout << "(" << x << "," << y << ")"; | |
if (--S) cout << " "; | |
} | |
cout << "\n"; | |
} | |
int main() | |
{ | |
while (getline(cin, str)) | |
{ | |
init(); | |
read(); | |
Andrews_Monotone_Chain(); | |
print(); | |
} | |
} |