题意:给定图上的几个点,求包括这几个点(但是不能经过)的最小的多边形的周长(只能用单元格的对角线和边来连接多边形)
思路:凸包转化。将每个点扩展成周围的4个点,然后对这些点进行离散化,最终计算边缘点的距离和即可。最后计算距离的时候要讲两点间的距离转化成由单元格的对角线和边组成的折线的长才可以。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const int maxn = 102400;
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){}
bool operator <(const P &a)const
{
if(x!=a.x)return x < a.x;
return y < a.y;
}
P operator -(P p)
{
return P(add(x,-p.x),add(y,-p.y));
}
double dot(P p)
{
return add(x *p.x,y*p.y);
}
double det(P p)
{
return add(x*p.y,-y*p.x);
}
};
vector<P> convex_hull(P* ps,int n)
{
sort(ps,ps+n);
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)
{
if(fabs(p.x - q.x) == fabs(p.y - q.y))
return sqrt(2.0)*fabs(p.x - q.x);
else
{
double dx = fabs(p.x - q.x);
double dy = fabs(p.y - q.y);
double minn = min(dx,dy);
return minn*sqrt(2.0) + dx -minn + dy - minn;
}
}
int n;
P ps[maxn*4];
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i = 0;i < n;i++)
{
double x,y;
scanf("%lf%lf",&x,&y);
ps[i*4].x = x-1;ps[i*4].y = y;
ps[i*4+1].x = x;ps[i*4+1].y = y-1;
ps[i*4+2].x = x;ps[i*4+2].y = y+1;
ps[i*4+3].x = x+1;ps[i*4+3].y = y;
}
vector<P> qs = convex_hull(ps,n*4);
double ans = 0.000000;
for(int i = 0;i < qs.size();i++)
ans += dist(qs[i],qs[(i+1)%qs.size()]);
printf("%f\n",ans);
}
return 0;
}