【P2742】包围奶牛

嘛开学了佛系更,另外CSP也不远了

如题,随便找篇blog就能好好学习的东西 。。

这篇,大意是:观察到一个包从最左边的点走下半部分到最右边围起来的点斜率大小单调上升。上半部分类似

实现仔细想想应该不难(吧),拿下半部分为例:首先从左到右从下到上给点们排序,拿个栈来存点们,目标是到最后让栈内的点全都是下/上部分包围圈所需的点。一开始往栈里放拍最前两个点,然后开始加点:

如果新加进去的点与栈尾点的斜率比栈尾点与倒数第二个点的斜率大(如图,红点是栈内点),即形成包围态势,则直接让新点入栈。

(让黑点进了栈

 

否则:如图,新加进去的点(4)与栈尾点(3)的斜率比栈尾点(3)与倒数第二个点(2)的斜率小

 

 则不是包围态势。此时踢掉点三(它不是包上的点):

 

再次检查,发现新加进去的点(4)与栈尾点(2)的斜率比栈尾点(2)与倒数第二个点(1)的斜率小,还不是包围态势,所以重复一次上面的操作,踢掉点二:

 

 此时没什么好检查的了,把4点入栈,直接开始加下一个点。

如此反复直到对所有点都进行了一次入栈的操作并在期间踢出不满足条件的点。最后栈内只剩下下半部分包的点。一个个拿出来算距离和。

上半部分类似啦。

然后注意一点,两点组成的包就是两点间距离*2,要围起来的嘛。别做那些奇奇怪怪的剪纸就没问题力

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<stack>
#include<cmath>
#define MAXN 1000001
#define spc 1010101010 //特判k不存在 
using namespace std;
int N;
double ans;
struct cows{double x,y;}cow[10001];
stack<cows>zhan;

inline double caldis(cows a, cows b){return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));}//卡常成性 
inline double slope(cows a, cows b){return b.x==a.x ? spc : (b.y-a.y)/(b.x-a.x);}//计算a发射到b的斜率(斜率是slope这个没问题吧 
bool cmp(cows a, cows b){return a.x==b.x ? a.y<b.y : a.x<b.x ;}

int main(){
    cin>>N;
    for(int i=1; i<=N; i++)
    cin>>cow[i].x>>cow[i].y;
    
    if(N<=1){printf("0.00");return 0;}
    if(N==2){ans=2*caldis(cow[1],cow[2]);printf("%.2lf",ans);return 0;}
    sort(cow+1,cow+1+N,cmp);
    
    //现在开始搜包的下半边。 
    zhan.push(cow[1]);
    zhan.push(cow[2]);
    int j=3;
    double k=slope(cow[1],cow[2]);
    while(j<=N)
    {
        cows c=zhan.top();
        
        while(slope(c,cow[j])<k)
        {
            zhan.pop();
            c=zhan.top();
            zhan.pop();
            if(zhan.empty()){
                zhan.push(c);
                k=slope(c,cow[j]);
                continue;
            }
            k=slope(zhan.top(),c);
            zhan.push(c);
        }
        zhan.push(cow[j]);
        k=slope(c,cow[j]);
        j++;
    }
    //现在开始把下半边周长算上

    cows nowcow=zhan.top();
    zhan.pop();
    while(!zhan.empty())
    {
        ans+=caldis(nowcow,zhan.top());
        nowcow=zhan.top();
        zhan.pop();
    }
    //现在开始搜包的上半边。
    zhan.push(cow[1]);
    zhan.push(cow[2]);
    j=3;
    k=slope(cow[1],cow[2]);
    while(j<=N)
    {
        cows c=zhan.top();
        
        while(slope(c,cow[j])>k)
        {
            zhan.pop();
            c=zhan.top();
            zhan.pop();
            if(zhan.empty()){
                zhan.push(c);
                k=slope(c,cow[j]);
                continue;
            }
            k=slope(zhan.top(),c);
            zhan.push(c);
        }
        zhan.push(cow[j]);
        k=slope(c,cow[j]);
        j++;
    }
    //现在开始把上半边周长算上

    nowcow=zhan.top();
    zhan.pop();
    while(!zhan.empty())
    {
        ans+=caldis(nowcow,zhan.top());
        nowcow=zhan.top();
        zhan.pop();
    }
    printf("%.2lf",ans);
}

 

posted @ 2019-09-17 17:30  Snowysniper  阅读(139)  评论(1编辑  收藏  举报