凸包Graham扫描法->HDU3847

原创 2016年08月30日 00:29:27

Graham扫描法求凸包

凸包定义:

点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内。

凸包最常用的凸包算法是Graham扫描法和Jarvis步进法。

Graham扫描法:

首先,找到所有点中最左边的(y坐标最小的),如果y坐标相同,找x坐标最小的.

以这个点为基准求所有点的极角(atan2(y-y0,x-x0)),并按照极角对这些点排序,前述基准点在最前面,设这些点为P[0]..P[n-1].

PS:这样预处理后,保证p[0],p[1]和p[n-1]都是凸包上的点.

建立一个栈,初始时P[0]、P[1]、P[2]进栈,对于 P[3..n-1]的每个点,若栈顶的两个点与它不构成”向左转”的关系,则将栈顶的点出栈,直至没有点需要出栈以后将当前点进栈;
所有点处理完之后栈中保存的点就是凸包了。

图示:
这里写图片描述


HDU3847

题意:

求能让一个给出的图形通过缝隙的最小宽度。

题解:

用这些点构造一个凸包,枚举凸包的各个边,求凸包上其他点到这个边的距离的最大值中的最小值。

代码:

#include <stdio.h>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <float.h>
using namespace std ;
#define MAX 110
const double eps = 1e-8 ;
int sgn(double x)
{
    if(fabs(x) < eps) return 0 ;
    if(x < 0) return -1 ;
    else return 1 ;
}
struct Point
{
    double x , y ;
    Point(){}
    Point(double _x , double _y)
    {
        x = _x ; y = _y ;
    }
    Point operator - (const Point &b) const
    {
        return Point(x - b.x , y - b.y) ;
    }
    double operator ^ (const Point &b) const
    {
        return x*b.y - y*b.x ;
    }
    double operator * (const Point &b) const
    {
        return x*b.x + y*b.y ;
    }
};
struct Line
{
    Point s , e ;
    Line(){}
    Line(Point _s , Point _e)
    {
        s = _s ; e = _e ;
    }
};
double xmult(Point p0,Point p1,Point p2) //叉积p0p1 X p0p2
{
    return (p1-p0)^(p2-p0);
}
double dist(Point a ,Point b)
{
    return sqrt((b - a) * (b - a)) ;
}
double PointToLine(Point p ,Line L)
{
    Point result ;
    double t = ((p-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
    result.x=L.s.x+(L.e.x-L.s.x)*t ;
    result.y=L.s.y+(L.e.y-L.s.y)*t ;
    return dist(p , result) ;
}
Point list[MAX] ;
int Stack[MAX] , top ;
bool _cmp(Point p1,Point p2)
{
    double tmp = (p1-list[0])^(p2-list[0]);
    if(sgn(tmp) > 0)return true;
    else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0)
        return true;
    else return false;
}
void anglesort(int n) //输入,并把最左下方的点放在list[0],并且进行极角排序
{
    int i,k;
    Point p0;
    scanf("%lf%lf",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        scanf("%lf%lf",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,_cmp);
}
void Graham(int n)
{
    Point p0;
    int k = 0;
    p0 = list[0];
    //找最下边的一个点
    for(int i = 1;i < n;i++)
    {
        if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) )
        {
            p0 = list[i];
            k = i;
        }
    }
    swap(list[k],list[0]);
    sort(list+1,list+n,_cmp);
    if(n == 1)
    {
        top = 1;
        Stack[0] = 0;
        return;
    }
    if(n == 2)
    {
        top = 2;
        Stack[0] = 0;
        Stack[1] = 1;
        return ;
    }
    Stack[0] = 0;
    Stack[1] = 1;
    top = 2;
    for(int i = 2;i < n;i++)
    {
        while(top > 1 && sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0)
            top--;
        Stack[top++] = i;
    }
    //for(int i = 0 ; i < top ; i ++) printf("%d\n" , Stack[i]);
}
double solve()
{
    Line ll ;
    double x , y , ans , temp;
    ans = DBL_MAX ;
    ll = Line(list[Stack[0]] , list[Stack[top - 1]]) ;
    for(int k = 0 ; k < top ; k ++)
    {
        if(k != 0 && k != top-1)
            temp = max(temp , PointToLine(list[Stack[k]] , ll)) ;
    }
    ans = min(ans , temp) ;
    for(int i = 0 ; i < top - 1 ; i ++)
    {
        int j = i + 1 ;
        ll = Line(list[Stack[i]] , list[Stack[j]]) ;
        temp = 0.0 ;
        for(int k = 0 ; k < top ; k ++)
        {
            if(k != i && k != j)
                temp = max(temp , PointToLine(list[Stack[k]] , ll)) ;
                //cout << temp << endl ;
        }
        ans = min(ans , temp) ;
    }
    return ans ;
}
int main()
{
    int n , cas = 1 , len;
    while(scanf("%d" , &n)!=EOF , n)
    {
        anglesort(n) ;
        Graham(n) ;
        printf("Case %d: %.2f\n",cas++, solve() + 0.005);
    }
    return 0 ;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

POJ 1113 && HDU 1348 Wall (凸包周长 graham扫描法)

POJ 1113 && HDU 1348 Wall (凸包周长 graham扫描法)

关于凸包——Graham扫描法

首先是凸包的第一种解法,graham扫描法。算法的步骤如下: 1 首先我们要找到凸包的一个顶点,这个顶点的y坐标要最小,相同的y的情况下,选择更靠左的点 2 对给出的顶点集进行排序,按照极角递增的顺序...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

POJ 2187-Beauty Contest(凸包-Graham扫描法/旋转卡壳法)

Beauty Contest Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 36053  ...

凸包问题的Graham扫描法

格雷厄姆扫描法是利用平面上任意3 点所构成的回路是左转还是右转的判别法来求平面点集的凸包。 1.三角区符号的计算 点o(a,b),p(c,d),q(e,f)是平面上的任意三点,D=ab+cf+eb...

寻找凸包(Graham扫描法)

题意描述:对任意给定的平面上的点集,求最小凸多边形使得点集中的点要么在凸多边形的边上,要么在凸多边形的内部。Graham算法描述: 在所有的点中找到一点p0,使得p0的纵坐标值最小,在有多个最小纵坐标...

寻找凸包的graham 扫描法

1,点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内。  2,凸包最常用的凸包算法是Graham扫描法和Jarvis步进法。  3,Graham扫...

凸包graham扫描法

import java.util.*; public class ConvexHull { private static Point[] p; private static Point p1;...

Hdu1348凸包graham——scan法

题意:一个国王要求建筑师修一堵墙,围绕他的城堡,且墙与城堡之间的距离总不小于L输入节点和L求周长 解析:此题是求凸包但是有变形,因为多了一个L可以这样想,墙除了在顶点处的延生出去是个弧形意外其他的地...

HDU3847 Trash Removal(凸包)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3847 Trash Removal Time Limit: 2000/1000 MS (Java...

hdu 3847 Trash Removal 2011WorldFinal 凸包

/* 求出多边形最窄的地段长度 枚举边,求出所有点中到边的距离最大的值 这些值中最小的就是答案 */ #include #include #include #include const int...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)