模板题链接:https://www.luogu.org/problemnew/show/P2742
感觉比较详细的教程:https://www.luogu.org/blog/cyx-TombRaider/p2742-mu-ban-er-wei-tu-bao-by-hydranazis
求凸包有两种主要的方法:极角序、水平序
然而ysy在某咕网校说极角序容易挂……所以本人学了水平序求凸包的方法
先按坐标排序
找到左下角的点
我们把整个凸包分成上凸包和下凸包两部分求
对于每个点,先进栈
如果它进栈之后还是一个凸包的结构,我们就把它加入栈中
而后来如果该节点被判断为不是凸包上的点,就弹栈
最后算周长的时候两部分分开算,再相加。
代码:
首先是定义结构体存储点
#include <bits/stdc++.h>
using namespace std;
struct Point {
double x, y;
} point[10010];
int n;
double ans;
需要用到的函数:
double dis(double xa, double ya, double xb, double yb) {
return sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb));
}
double check(int i, int j, int k) {
return (point[i].y - point[j].y) * (point[k].x - point[j].x) < (point[k].y - point[j].y) * (point[i].x - point[j].x);
}
dis返回两点间距离,check比较斜率(又因为斜率=tan(倾斜角),所以也就是在比较倾斜角)大小
排序的比较函数:
bool cmp(Point a, Point b) {
return a.y == b.y ? a.x < b.x : a.y < b.y;
}
按照坐标排序,如果纵坐标不相等比较纵坐标否则比较横坐标,这样排序出来的第一个点肯定是左下角的点。
主程序:
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> point[i].x >> point[i].y;
}
sort(point + 1, point + n + 1, cmp);
stack < int > s;
s.push(1); s.push(2);
for(int i = 3; i <= n; i++) {
while(s.size() > 1) {
int k = s.top();
s.pop();
int k2 = s.top();
s.push(k);
if(check(k2, s.top(), i)) s.pop(); else break;
}
s.push(i);
}
int k = s.top();
s.pop();
while(!s.empty()) {
ans += dis(point[k].x, point[k].y, point[s.top()].x, point[s.top()].y);
k = s.top();
s.pop();
}
s.push(1); s.push(2);
for(int i = 3; i <= n; i++) {
while(s.size() > 1) {
int k = s.top();
s.pop();
int k2 = s.top();
s.push(k);
if(!check(k2, s.top(), i)) s.pop(); else break;
}
s.push(i);
}
k = s.top();
s.pop();
while(!s.empty()) {
ans += dis(point[k].x, point[k].y, point[s.top()].x, point[s.top()].y);
k = s.top();
s.pop();
}
printf("%.2lf", ans);
return 0;
}
学过了凸包就可以做旋转卡壳的题目了,然而遇到旋转卡壳的题目窝只会口胡,不会打码 = = 可见我还是太弱了QAQ以后再填坑吧