凸包问题

来源:互联网 发布:php广告任务网源码 编辑:程序博客网 时间:2024/05/22 05:28

根据极角排序Graham扫描法求凸包(但无法完全保留凸包边上的点)

1. 找出最左下的点(首先要最下,有多个最下则找最左),记为p[0]

2. 以p[0]为原点,对p[1]...p[n-1]进行按极角排序。极角相同的,距离p[0]近的算小
3. 栈里面放入p[0],p[1],p[2]

for(int i = 3; i < n; ++i) {

while(true) {

    考察栈顶元素 k2,k2下方元素k1,以及p[i]
考虑 k1->k2->p[i]
if( 在k2这一点直走或者向右拐了) {
将k2出栈
else break;
}
p[i]入栈
}

4. 栈中的点就是凸包的所有顶点

//极角序 Graham扫描法struct Point{double x,y;Point(double x,double y) :x(x),y(y){}Vector operator - (const Point& p){return Vector(x-p.x,y-p.y);}bool operator < (const Point& p) const {  //注意是取下左点,最下中的最左 if(p.y==y) return x<p.x;return y<p.y;}};vector<Point> points;vector<Point> stack;double cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}int Sign(double x){ if(fabs(x)<EPS) return 0;return x<0?-1:1;}double dist(const Point& a,const Point& b){return hypot(fabs(a.x-b.x),fabs(a.y-b.y));}struct cmp{Point p0;cmp(Point p):p0(p){}bool operator () (Point p1,Point p2) const {int s=Sign(cross(p1-p0,p2-p0));if(s>0) return true;else if(s<0) return false;else {if(dist(p1,p0)<dist(p0,p2)) return true;else return false;}}};int Graham(){if(points.size()<3) return 0;stack.clear();sort(points.begin(),points.end()); //找出下左的点 sort(points.begin()+1,points.end(),cmp(points[0]));stack.push_back(points[0]); stack.push_back(points[1]); stack.push_back(points[2]);for(int i=3;i<points.size();i++){for(;;){Point p2=*(stack.end()-1);Point p1=*(stack.end()-2);if(Sign(cross(p2-p1,points[i]-p2))<=0) //小于零代表向右拐或直走 stack.pop_back();else break;}stack.push_back(points[i]); //i点肯定是向右拐的 }}

根据水平排序Graham扫描法求凸包(可以求出凸包边上的点,就是比极角序的麻烦)

判断的方法是否是凸包的方法和极角的一样,就是求一边只求出了一半的凸包,还要倒着扫一遍点

//水平序Graham扫描法求凸包struct Point{double x,y;Point(double x,double y) :x(x),y(y){}Vector operator - (const Point& p){return Vector(x-p.x,y-p.y);}bool operator < (const Point& p) const {  //注意取下左点 if(p.y==y) return x<p.x;return y<p.y;}};vector<Point> points;vector<Point> stack;double cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}int Sign(double x){ if(fabs(x)<EPS) return 0;return x<0?-1:1;}double dist(const Point& a,const Point& b){return hypot(fabs(a.x-b.x),fabs(a.y-b.y));}int Graham(){if(points.size()<3) return 0;stack.clear();sort(points.begin(),points.end());stack.push_back(points[0]);stack.push_back(points[1]);int n=points.size(); for(int i=2;i<n;i++){while(stack.size()>1){  //一定要这一条,因为第二个点不一定是凸包可能会pop,而极角排序的肯定是凸包中的点 Point p2=*(stack.end()-1);Point p1=*(stack.end()-2);if(Sign(cross(p2-p1,points[i]-p2))<0) //不加等于,可以保留凸包上的点 stack.pop_back();else break;}stack.push_back(points[i]);} int size=stack.size();stack.push_back(points[n-2]); //因为此时栈顶元素是points[n-1],下一个就是n-2for(int i=n-3;i>=0;i--){while(stack.size()>size){Point p2=*(stack.end()-1);Point p1=*(stack.end()-2);if(Sign(cross(p2-p1,points[i]-p2))<0)stack.pop_back();else break;}stack.push_back(points[i]);}stack.pop_back(); //points[0]被重复push两次了 } 


0 0