Share the Ruins Preservation(Graham算法利用叉积动态维护上下凸壳)

Two organizations International Community for Preservation of Constructions (ICPC) and Japanese Archaeologist Group (JAG) engage in ruins preservation. Recently, many ruins were found in a certain zone. The two organizations decided to share the preservation of the ruins by assigning some of the ruins to ICPC and the other ruins to JAG.

Now, ICPC and JAG make a rule for assignment as follows:

1.Draw a vertical straight line from the north to the south, avoiding to intersect ruins.
2.Ruins located to the west of the line are preserved by ICPC. On the other hand, ruins located to the east of the line are preserved by JAG. (It is possible that no ruins are located to the east/west of the line; in this case, ICPC/JAG will preserve no ruins.)
A problem is where to draw a straight line. For each organization, the way to preserve its assigned ruins is to make exactly one fence such that all the assigned ruins are in the region surrounded by the fence. Furthermore, they should minimize the length of such a fence for their budget. If the surrounded areas are vast, expensive costs will be needed to maintain the inside of areas. Therefore, they want to minimize the total preservation cost, i.e. the sum of the areas surrounded by two fences. Your task is to write a program computing the minimum sum of the areas surrounded by two fences, yielded by drawing an appropriate straight line.

输入

The input consists of a single test case.

N
x1 y1
x2 y2
...
xN yN

The first line contains an integer N (1≤N≤100,000), which is the number of founded ruins. The following N lines represent the location of the ruins. The i-th line of them consists of two integers xi and yi, which indicate the location of the i-th ruin is xi east and yi north from a certain location in the zone. You can assume the following things for the ruins:

−109≤xi,yi≤109
You can ignore the sizes of ruins. That is, you can assume ruins are points.
No pair of ruins has the same location.

输出

Print the minimum total preservation cost yielded by drawing an appropriate straight line. You should round off the cost to the nearest integer.

样例输入

复制样例数据

8
-10 0
-10 5
-5 5
-5 0
10 0
10 -5
5 -5
5 0

样例输出

50

#include <bits/stdc++.h>
using namespace std;
const long double eps=1e-8;
const int maxn=1e5+10;
typedef __int128  ll;
struct point
{
    ll x,y;
} a[maxn];
bool cmp(point r,point t)
{
    if(r.x==t.x)
        return r.y<t.y;
    return r.x<t.x;
}
bool mult(point sp,point ep,point op)
{
    return (sp.x-op.x)*(ep.y-op.y)>=(ep.x-op.x)*(sp.y-op.y);;
}
ll area(point a,point b){
    return a.x*b.y-a.y*b.x;
}
vector<long double>posi;
vector<point>up,down;
__int128 le_ri[maxn<<1],ri_le[maxn<<1];
int main()
{
    int n,cnt;
    scanf("%d",&n);
    long long tx,ty;
    for(int i=1; i<=n; i++)
    {
        scanf("%lld%lld",&tx,&ty);
        a[i].x=tx;
        a[i].y=ty;
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1; i<=n; i++)
    {
        if(i==1||a[i].x!=a[i-1].x)
        {
            posi.push_back(a[i].x-eps);
            posi.push_back(a[i].x+eps);
        }
    }
    int l=0;
    for(int i=0; i<posi.size(); i++)
    {
        __int128 changeup=0,changedown=0;
        for(int j=l+1; j<=n; j++)
        {
            if(a[j].x<posi[i])
            {
                if(up.size()==0)
                {
                    up.push_back(a[j]);
                }
                else if(up.size()==1)
                {
                    up.push_back(a[j]);
                    changeup+=area(up[1],up[0]);
                }
                else
                {
                    while(up.size()>=2&&!mult(a[j],up[up.size()-1],up[up.size()-2]))
                    {
                        changeup-=area(up[up.size()-1],up[up.size()-2]);
                        up.pop_back();
                    }
                    up.push_back(a[j]);
                    changeup+=area(up[up.size()-1],up[up.size()-2]);
                }
                if(down.size()==0)
                {
                    down.push_back(a[j]);
                }
                else if(down.size()==1)
                {
                    down.push_back(a[j]);
                    changedown+=area(down[0],down[1]);
                }
                else
                {
                    while(down.size()>=2&&mult(a[j],down[down.size()-1],down[down.size()-2]))
                    {
                        changedown-=area(down[down.size()-2],down[down.size()-1]);
                        down.pop_back();
                    }
                    down.push_back(a[j]);
                    changedown+=area(down[down.size()-2],down[down.size()-1]);
                }
                l=j;
            }
            else
            {
                break;
            }
        }
        if(i==0)
            le_ri[i]=changedown+changeup;
        else
            le_ri[i]=le_ri[i-1]+changedown+changeup;
    }
    down.clear();
    up.clear();
    int r=n+1;
    for(int i=posi.size()-1; i>=0; i--)
    {
        __int128 changeup=0,changedown=0;
        for(int j=r-1; j>=1; j--)
        {
            if(a[j].x>posi[i])
            {
                if(up.size()==0)
                {
                    up.push_back(a[j]);
                }
                else if(up.size()==1)
                {
                    up.push_back(a[j]);
                    changeup+=area(up[1],up[0]);
                }
                else
                {
                    while(up.size()>=2&&!mult(a[j],up[up.size()-1],up[up.size()-2]))
                    {
                        changeup-=area(up[up.size()-1],up[up.size()-2]);
                        up.pop_back();
                    }
                    up.push_back(a[j]);
                    changeup+=area(up[up.size()-1],up[up.size()-2]);
                }
                if(down.size()==0)
                {
                    down.push_back(a[j]);
                }
                else if(down.size()==1)
                {
                    down.push_back(a[j]);
                    changedown+=area(down[0],down[1]);
                }
                else
                {
                    while(down.size()>=2&&mult(a[j],down[down.size()-1],down[down.size()-2]))
                    {
                        changedown-=area(down[down.size()-2],down[down.size()-1]);
                        // cout<<down[down.size()-1].x<<" "<<down[down.size()-1].y<<" "<<down[down.size()-2].x<<" "<<down[down.size()-2].y<<endl;
                        down.pop_back();
                    }
                    down.push_back(a[j]);
                    changedown+=area(down[down.size()-2],down[down.size()-1]);
                }
                r=j;
            }
            else
            {
                break;
            }
        }
        if(i==posi.size()-1)
            ri_le[i]=changedown+changeup;
        else
            ri_le[i]=ri_le[i+1]+changedown+changeup;
    }
    __int128 ans=9000000000000000000;
    for(int i=0; i<posi.size(); i++)
    {
        ans=min(ans,le_ri[i]+ri_le[i]);
    }
    printf("%lld\n",(long long )((ans+1)/2));
    return 0;
}

 

原文地址:https://www.cnblogs.com/xiaolaji/p/11517935.html

时间: 2024-10-14 09:19:53

Share the Ruins Preservation(Graham算法利用叉积动态维护上下凸壳)的相关文章

Graham算法—二维点集VC++实现

一.凸包定义 通俗的说就是:一组平面上的点,求一个包含所有点的最小凸多边形,这个最小凸多边形就是凸包. 二.Graham算法思想 概要:Graham算法的主要思想就是,最终形成的凸包,即包围所有点的凸多边形,假定多边形是按逆时针方向生成的,那么多边形内部包围的所有点与多边形每个有向边的关系都是:点在有向边的左边.依照此思想,只要找到一个出发点,然后依此出发点按逆时针方向构建多边形,并保证每加入一条有向边时,都要满足其余点都在该边的左边. ***点与线的关系定义:平面上的三点P1(x1,y1),P

【改革春风吹满地 HDU - 2036 】【计算几何-----利用叉积计算多边形的面积】

利用叉积计算多边形的面积 我们都知道计算三角形的面积时可以用两个邻边对应向量积(叉积)的绝对值的一半表示,那么同样,对于多边形,我们可以以多边形上的一个点为源点,作过该点并且过多边形其他点中的某一个的多条射线,这样就可以把该多边形变为多个三角形,然后利用叉积求面积即可. 不过要注意,对于三角形可以简单的用叉积的绝对值的一半表示,但对于多边形不可随意将它分割成的几个三角形对应的叉积的绝对值相加,要有一定顺序才可. 对于三角形,有 [该图片来源:https://www.cnblogs.com/xie

Graham算法模板

Graham算法模板 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 typedef long long ll; 8 const int maxn=1100; 9 const double pi=acos(-1.0); 10 struct

MVVM下 利用反射动态创建ViewModel 实现单例

在MVVM一般情况下都会希望ViewModel 在整个应用程序中只有一份实例 传统的做法是用单例模式去实现 : public class ViewModelTest { private ViewModelTest() { } private static ViewModelTest viewModelInstace; public static ViewModelTest GetViewModelTestInstace() { if (viewModelInstace == null) { vi

算法笔记-DTW动态时间规整

算法笔记-DTW动态时间规整 简介 简单的例子 定义 讨论 约束条件 步模式 标准化 点与点的距离函数 具体应用场景 分类 点到点匹配 算法笔记-DTW动态时间规整 动态时间规整/规划(Dynamic Time Warping, DTW)是一个比较老的算法,大概在1970年左右被提出来,最早用于处理语音方面识别分类的问题. 1.简介 简单来说,给定两个离散的序列(实际上不一定要与时间有关),DTW能够衡量这两个序列的相似程度,或者说两个序列的距离.同时DTW能够对两个序列的延展或者压缩能够有一定

利用Java动态生成 PDF 文档

利用Java动态生成 PDF 文档,则需要开源的API.首先我们先想象需求,在企业应用中,客户会提出一些复杂的需求,比如会针对具体的业务,构建比较典型的具备文档性质的内容,一般会导出PDF进行存档.那么目前最佳的解决方案,你可能会想到 iText ,对没错... iText+(Velocity / Freemarker)可以实现.不过据我熟悉,iText本身提供的HTML解析器还是不够强大,许多HTML标签和属性无法识别,更悲催的是简单的CSS它不认识,排版调整样式会让你头大的.不要失望,接下来

利用反射动态加载程序集中所有的继承于Form的子类

利用C# 的反射,能够轻松快捷的创建指定类型的未知对象,比如继承某个接口的类,继承于某个基类的子类. 问题场景: 我自己创建一个解决方案,这个方案里面放了很多的小工具,每一个工具都是一个小窗体,于是,我就用一个MID窗体来包含这些窗体. 这样问题就来了,每一次我添加一个小工具,我就必须在MID窗体里面添加一个按钮,或者是一个菜单.在事件写上,让某个窗体显示出来.这类无聊的语句. 那么能不能让程序自动查找程序集中的窗体,自动创建按钮,或者菜单. 这样就可以达到动态创建的目的了 解决方案: 假设我们

java反射并不是什么高深技术,面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象

java反射并不是什么高深技术,面向对象语言都有这个功能. 面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象,去获取类相关的信息 2.利用java反射可以调用类的私有方法么?private()方法 答:可以,class取出method,method继承executable类,executable类继承AccessibleObject类,AccessibleObject有个setAccessiable()设置这个方法是否可访问. 则设置成true,就可将pr

利用 Flask 动态展示 Pyecharts 图表数据的几种方法

Pyecharts 官网 http://gallery.pyecharts.org/#/README 利用 Flask 动态展示 Pyecharts 图表数据的几种方法 https://www.jianshu.com/p/6910712e9b64 Python可视化神器——pyecharts的超详细使用指南 https://www.jianshu.com/p/554d64470ec9 原文地址:https://www.cnblogs.com/hzjdpawn/p/12684906.html