将每个点分成上下左右四个点加入图中,求出凸包,由于只有长度为sqrt(2.0)和1的边,所以按照横坐标差值和纵坐标差值处理即可,代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn = 400007;
double EPS = 1e-10;
double add(double a, double b) {
if(abs(a+b) < EPS * (abs(a)+abs(b))) return 0;
return a+b;
}
struct P {
double x, y;
P() {}
P(double x, double y) : x(x), y(y) {}
P operator + (P p) { return P(add(x, p.x), add(y, p.y)); }
P operator - (P p) { return P(add(x,-p.x), add(y,-p.y)); }
P operator * (double d) { return P(x*d, y*d); }
double dot(P p) { return add(x*p.x, y*p.y); }
double det(P p) { return add(x*p.y, -y*p.x); }
};
bool cmp_x(const P& p, const P& q) {
if(p.x != q.x) return p.x < q.x;
return p.y < q.y;
}
vector<P> convex_hull(P* ps, int n) {
sort(ps, ps+n, cmp_x);
int k = 0;
vector<P> qs(n*2);
for(int i = 0; i < n; ++i) {
while(k > 1 && (qs[k-1]- qs[k-2]).det(ps[i] - qs[k-1]) <= 0 ) k--;
qs[k++] = ps[i];
}
for(int i = n-2, t = k; i >= 0; --i) {
while(k > t && (qs[k-1] - qs[k-2]).det(ps[i]-qs[k-1]) <= 0) k--;
qs[k++] = ps[i];
}
qs.resize(k-1);
return qs;
}
double dist(P p, P q) {
return (p-q).dot(p-q);
}
int N;
P ps[maxn];
void solve(int n) {
vector<P> qs = convex_hull(ps, n);
double res = 0.0;
int kk = qs.size();
double two = sqrt(2.0);
for(int i = 0; i < kk; ++i) {
int t1 = abs(qs[i].x-qs[(i-1+kk)%kk].x), t2 = abs(qs[i].y-qs[(i-1+kk)%kk].y);
res += abs(t1-t2);
res += (double)1.0*min(t1, t2)*two;
}
printf("%.5lf\n", res);
}
int main() {
int n;
while(~scanf("%d", &n)) {
int cnt = 0;
for(int i = 0; i < n; ++i) {
double x, y; scanf("%lf%lf", &x, &y);
ps[cnt].x = x+1;
ps[cnt++].y = y;
ps[cnt].x = x;
ps[cnt++].y = y+1;
ps[cnt].x = x-1;
ps[cnt++].y = y;
ps[cnt].x = x;
ps[cnt++].y = y-1;
}
solve(cnt);
}
}