# 題目: UVa 11096 - Nails
# 題目說明
給N個點 (x, y平面座標),求這些點形成的凸包(Convex Hull)周長
INPUT:
第一行輸入一個整數T,代表測資數
每筆測資輸入L、N,代表橡皮筋長度、點的數量
接下來有N行,每行輸入兩個變數(x, y),為點的座標
OUTPUT:
輸出 MAX(凸包(Convex Hull)周長,L)
# 解題方法
- 如果使用
Graham's Scan演算法需要做極角排序 - 使用
Andrew's Monotone Chain演算法
將凸包算出後再兩兩計算長度,加總即為周長
涉及小數,所以題中變數盡量用double
# 參考程式碼 Graham's Scan
#include <iostream>
#include <vector>
#include <algorithm>
#include <math.h>
#include <iomanip>
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;
int T, N;
double L;
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()
{
double a, b;
cin >> L >> N;
for (int i = 0; i < N; ++i) cin >> 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 < N; ++i) V[i].d = dist(V[0], V[i]);
sort(V.begin() + 1, V.end(), cmp);
for (int i = 0; i < N; ++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]);
}
ret.emplace_back(V[0]);
}
void print()
{
double ans = 0;
for (int i = 1; i < ret.size(); ++i) ans += dist(ret[i - 1], ret[i]);
cout << setprecision(5) << fixed << max(ans, L) << "\n";
}
int main()
{
cin >> T;
while (T--)
{
init();
read();
GrahamScan();
print();
}
}
# 參考程式碼 Andrew's Monotone Chain
#include <iostream>
#include <vector>
#include <algorithm>
#include <math.h>
#include <iomanip>
using namespace std;
struct point
{
double x;
double y;
};
int T, N;
double L;
vector<point> V;
vector<point> ret;
static auto fast_io = []
{
ios::sync_with_stdio(false);
cout.tie(nullptr);
cin.tie(nullptr);
return 0;
}();
void init()
{
V.clear();
ret.clear();
}
void read()
{
int a, b;
cin >> L >> N;
for (int i = 0; i < N; ++i) cin >> 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 < N; ++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 = N - 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]);
}
}
double dis(point& a, point& b)
{
return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}
void print()
{
double ans = 0;
for (int i = 0; i < ret.size() - 1; ++i) ans += dis(ret[i], ret[i + 1]);
cout << setprecision(5) << fixed << max(ans, L) << "\n";
}
int main()
{
cin >> T;
while (T--)
{
init();
read();
Andrews_Monotone_Chain();
print();
}
}
# 參考資料
https://github.com/morris821028/UVa/blob/master/volume110/11096%20-%20Nails.cpp
https://blog.csdn.net/mobius_strip/article/details/8453882