poj 1113 Wall 凸包模板题

题意:输入n和l,接着顺时针输入n个点。由n个点组成一个多边形,表示一座城堡。现在需要建设城墙,城墙至少需要距离城堡l远,问城墙最少需要建设多少长。

题解:

从题目中我们知道多边形可以使一个凹的,但是我们发现,在凹的地方直接作直线的城墙比弯曲的建更短(两点之间直线最短嘛)。最后排除点凹的地方后我们发现,剩余的图形就是一个凸多边形。我们用凸包模板求得边界,然后再求城墙。

在求城墙的时候,我们发现只有拐弯点是弧度的,其余的地方等于凸包的边长。而对于m点凸包,我们令总长弧度为x,那么根据多边形内角之和,以及拐角作垂线,我们可以得到方程x+(m-2)*180+m*90*2=m*360=>x=360,正好是一个圆的周长

那么结果ans=凸包的周长+2*pi*l;然后用(int)(ans+0.5)四舍五入即可。




代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
using namespace std;
//基础点和向量运算
struct Point{
    int x,y;
    Point(int x=0,int y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A,double p){return Vector(A.x*p,A.y*p);}
Vector operator / (Vector A,double p){return Vector(A.x/p,A.y/p);}
bool operator <(const Point& a, const Point& b)
{
    return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
int Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}//叉积

const int maxn=1e3+10;
const double pi=atan(1.0)*4;
int n;
Point p[maxn],ch[maxn];
int ConvexHull()//求凸包
{
    sort(p,p+n);
    int i,m=0,k;
    for(i=0;i<n;i++)
    {
        while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
        ch[m++]=p[i];
    }
    k=m;
    for(i=n-2;i>=0;i--)
    {
        while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
        ch[m++]=p[i];
    }
    if(n>1)m--;
    return m;
}
double dis(Point a,Point b)//求两点距离
{
    return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
    int l;
    while(scanf("%d%d",&n,&l)!=EOF)
    {
        int i,j,k,m;
        for(i=0;i<n;i++)
            scanf("%d%d",&p[i].x,&p[i].y);
        m=ConvexHull();
        double ans=0;
        for(i=1;i<m;i++)
            ans+=dis(ch[i],ch[i-1]);
        ans+=dis(ch[0],ch[m-1]);
        ans+=2.0*pi*l;
        printf("%d\n",int(ans+0.5));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值