Wall

发布时间 2023-08-12 12:08:53作者: Minza

Wall
时间限制(普通/Java):1000MS/3000MS 内存限制:64000KByte

描述

Once upon a time there was a greedy King who ordered his chief Architect to build a wall around the King's castle. The King was so greedy, that he would not listen to his Architect's proposals to build a beautiful brick wall with a perfect shape and nice tall towers. Instead, he ordered to build the wall around the whole castle using the least amount of stone and labor, but demanded that the wall should not come closer to the castle than a certain distance. If the King finds that the Architect has used more resources to build the wall than it was absolutely necessary to satisfy those requirements, then the Architect will loose his head. Moreover, he demanded Architect to introduce at once a plan of the wall listing the exact amount of resources that are needed to build the wall.

Your task is to help poor Architect to save his head, by writing a program that will find the minimum possible length of the wall that he could build around the castle to satisfy King's requirements.
The task is somewhat simplified by the fact, that the King's castle has a polygonal shape and is situated on a flat ground. The Architect has already established a Cartesian coordinate system and has precisely measured the coordinates of all castle's vertices in feet.

输入

The first line of the input file contains two integer numbers N and L separated by a space. N (3 <= N <= 1000) is the number of vertices in the King's castle, and L (1 <= L <= 1000) is the minimal number of feet that King allows for the wall to come close to the castle.
Next N lines describe coordinates of castle's vertices in a clockwise order. Each line contains two integer numbers Xi and Yi separated by a space (-10000 <= Xi, Yi <= 10000) that represent the coordinates of ith vertex. All vertices are different and the sides of the castle do not intersect anywhere except for vertices.

输出

Write to the output file the single number that represents the minimal possible length of the wall in feet that could be built around the castle to satisfy King's requirements. You must present the integer number of feet to the King, because the floating numbers are not invented yet. However, you must round the result in such a way, that it is accurate to 8 inches (1 foot is equal to 12 inches), since the King will not tolerate larger error in the estimates.

样例输入

9 100
200 400
300 400
300 300
400 300
400 400
500 400
500 200
350 200
200 200

样例输出

1628

思路
凸包模板题

凸包(Convex Hull)是一个计算几何(图形学)中的概念。
在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。X的凸包可以用X内所有点(X1,...Xn)的凸组合来构造.

通俗来讲就是平面里有很多钉子,用橡皮筋来围住所有钉子后形成的最大的形状,该形状是个凸多边形;

求凸包有两个 O(nlogn) 算法, Graham 扫描法 和 Andrew 算法

Graham 扫描法 是先找凸包上一点,然后进行极角排序,直接求出整个凸包

Andrew 算法 是先找凸包上一点,然后进行坐标排序,分别求上下半个凸包,然后合并

这里用的是Graham 扫描法

就是先确定凸包上一点,然后依次连接点,每次加入点时查询是否能把下一个点也包进去,能包进去就进行下一个点的判断,否则出站,将当前该点舍弃掉,遍历所有点后得到的形状就是凸包;

用算法表示即
先创建一个栈,把凸包上已经确定好的一点(坐标最左下角的点)入栈,然后依次判断,把栈顶两个点与当前遍历到的点比较:
若向量判断在同一边,则入栈,否则当前栈顶的点不是凸包的点,则出栈进行下一次栈顶两个点与当前遍历到的点判断。
遍历结束后栈里的点即凸包上的点

最后要计算凸包周长,需要把一开始确定的点入栈,然后依次遍历栈计算两两距离即可
该题还需要加上一个半径为l的圆;
AC代码

#include <bits/stdc++.h>
using namespace std;
double PI=acos(-1);
class Node
{
public:
    int x,y;
};
int stx=0x3f3f3f3f,sty=0x3f3f3f3f;
int Cha(Node a,Node b,Node c)
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
double dis(Node a,Node b)
{
    return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool fir(Node a,Node b){
    if(a.x==b.x)return a.y<b.y;
    return a.x<b.x;
}
bool cmp(Node a,Node b)
{
    int temp=Cha({stx,sty},a,b);
    if(temp)return temp>0;
    return dis({stx,sty},a)<dis({stx,sty},b);
}
void solve()
{
    int n,l;
    cin>>n>>l;
    int x,y;
    vector<Node>pos;
    for(int i=1;i<=n;i++)
    {
        cin>>x>>y;
        pos.push_back({x,y});
        if(x<stx||x==stx&&y<sty)
        {
            stx=x;
            sty=y;
        }
    }
    sort(pos.begin(),pos.end(),fir);
    sort(pos.begin()+1,pos.end(),cmp);
    vector<Node>st;
    int top=1;
    st.push_back(pos[0]);
    st.push_back(pos[1]);
    for(int i=2;i<n;i++)
    {
        if(Cha(st[top-1],st[top],pos[i])>0)st.push_back(pos[i]),top++;
        else
        {
            while (top>=1&&Cha(st[top-1],st[top],pos[i])<=0)st.pop_back(),top--;
            st.push_back(pos[i]);
            top++;
        }
    }
    st.push_back(pos[0]);top++;
    double ans=0;
    for(int i=0;i<top;i++)
    {
        ans+=dis(st[i],st[i+1]);
    }
    cout<<fixed<<setprecision(0)<<ans+PI*2*l<<endl;
}
signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int _;
    _=1;
//    cin>>_;
    while(_--)
    {
        solve();
    }
}