什么是凸包建议百度
使用Andrew算法
1.对坐标进行排序x为第一关键字,y为第二关键字。这样左下角和右上角的点一定在凸包上。
2从1->n枚举所有的点求下凸包,用单调栈维护凸包上的点。新加入的点一定要在旧点的左侧,如果不行弹出旧点直到不能弹出为止。
3从n-1->1枚举所有的点求上凸包,用单调栈维护凸包上的点。新加入的点一定要在旧点的左侧,如果不行弹出旧点直到不能弹出为止。
4判断方向是用点的叉积。
#include <bits/stdc++.h>
using namespace std;
typedef pair<double, double> pdd;
pdd a[10007];
const double PI = acos(-1.0);
int f[1007];
double dis(pdd a, pdd b) // 计算距离
{
return sqrt((a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second));
}
int sign(double s)
{
if (fabs(s) < 1e-6)
return 0;
else
{
if (s > 0)
return 1;
else
return -1;
}
}
double cross(double x1, double y1, double x2, double y2)//叉积判断方向
{
return x1 * y2 - x2 * y1;
}
double area(pdd a, pdd b, pdd c)
{
return cross(b.first - a.first, b.second - a.second, c.first - a.first, c.second - a.second);
}
void solve()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
scanf("%lf%lf", &a[i].first, &a[i].second);
sort(a, a + n);
if (n == 1)
{
printf("%.0f\n", 0);
}
else if (n == 2)
{
printf("%.0f\n", dis(a[0], a[1]));
}
else
{
vector<int> v;//单调栈维护凸包上的点
int tt = 0;
for (int i = 0; i < n; i++)//求下凸包
{
while (v.size() >= 2 && (tt = sign(area(a[v[v.size() - 2]], a[v[v.size() - 1]], a[i])) >= 0))
{
if (tt > 0)
f[v[v.size() - 1]] = 0;
v.pop_back();
}
v.push_back(i);
f[i] = 1;
}
f[0] = 0;
for (int i = n - 2; i >= 0; i--)//求上凸包
{
if (f[i])
continue;
while (v.size() >= 2 && (tt = sign(area(a[v[v.size() - 2]], a[v[v.size() - 1]], a[i])) >= 0))
{
v.pop_back();
}
v.push_back(i);
}
double res = PI * m * 2;
for (int i = 1; i < v.size(); i++)
{
res += dis(a[v[i - 1]], a[v[i]]);
}
printf("%.0f\n", res);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T = 1;
//cin >> T;
while (T--)
{
solve();
}
return 0;
}