题意:
在一个直角坐标系内给n个点的坐标 ,要求画一个多边形,
条件:
1、将所有的点都要包含进去(保障所有的点在多边形的内部,不在多边形的边上);
2、保证多边形的顶点坐标是整数;
3、多边形顶点之间的连线要么是一条水平竖直的直线,要么是一条45度的斜线;
在保证以上三种条件的情况下,保证多边形的周长最小,输出多边形的周长。
输入:
1
0 0
2
1 1
1 2
输出:
5.656
7.656854
分析:
当一个点的时候,最小的多边形是将该点周围的四个点连起来组成的多边形,这样是最小的。根据这种情况,将所有的点周围的点
都找出来,之后去重之后求凸包。
x=abs(res[i-1].x-res[i].x);
y=abs(res[i-1].y-res[i].y);
len+=abs(x-y)+min(x,y)*sqrt(2).
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=500005;
struct node
{
int x,y;
node(int a=0,int b=0):x(a),y(b){}
bool operator <(const node &r) const
{
return (x==r.x?y<r.y:x<r.x);
}
node operator -(node r)const
{
return node(x-r.x,y-r.y);
}
} m[maxn];
node res[maxn];
int n,top;
set <node> s;
int solve()
{
sort(m,m+n);
int num=0;
for(int i=0; i<n; i++)
{
while(num>1&&(1ll*(res[num-1]-res[num-2]).x*(m[i]-res[num-2]).y-1ll*(res[num-1]-res[num-2]).y*(m[i]-res[num-2]).x)<=0)
num--;
res[num++]=m[i];
}
int k=num;
for(int i=n-2; i>=0; i--)
{
while(num>k&&(1ll*(res[num-1]-res[num-2]).x*(m[i]-res[num-2]).y-1ll*(res[num-1]-res[num-2]).y*(m[i]-res[num-2]).x)<=0)
num--;
res[num++]=m[i];
}
if(n>1)
num--;
return num;
}
int main()
{
int t,x,y,px,py,pos,tmp,ans;
node kk;
double len=0;
set<node>::iterator si;
while(scanf("%d",&t)!=EOF)
{
py=-1;
s.clear();
len=0.0;
ans=0;
for(int i=0; i<t; i++)
{
scanf("%d%d",&x,&y);
kk.x=x-1;
kk.y=y;
s.insert(kk);
kk.x=x+1;
kk.y=y;
s.insert(kk);
kk.x=x;
kk.y=y+1;
s.insert(kk);
kk.x=x;
kk.y=y-1;
s.insert(kk);
}
n=s.size();
si=s.begin();
for(int i=0; i<n; i++)
{
m[i]=*si;
si++;
}
int tt=solve();
res[tt].x=res[0].x;
res[tt++].y=res[0].y;
for(int i=1; i<tt; i++)
{
x=abs(res[i-1].x-res[i].x);
y=abs(res[i-1].y-res[i].y);
len+=abs(x-y)+min(x,y)*sqrt(2);
}
printf("%.10lf\n",len);
}
return 0;
}