Graham Scan O(nlogn) poj1228稳定凸包

Graham Scan

1.找左下角点p[0] 

2.以p[0]为C极角排序(叉积 同角度 dis取min)

3.遍历叉积判断p[i]加进凸包队列后前面哪些点pop

可以保证在最差情况下也能在O(nlogn)的时间复杂度求出结果 

凸包面积:叉积(三角形面积)

凸包周长:直接dis

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
 
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int MaxN = 1e3 + 5;
 
int n,Top;
double L,Cir;
struct Point{
	double x,y;
	Point(double x = 0,double y = 0) : x(x),y(y) {}
}stack[MaxN],C,a[MaxN];
typedef Point Vector;
 
int dcmp(double x){//equal ?= 0
	if(fabs(x) < eps) return 0;
	else return x < 0 ? -1:1;
}
 
//运算符重载
Vector operator + (Vector A, Vector B){ return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Vector A, Vector B){ return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, double p){ return Vector(A.x*p, A.y*p); }
bool operator == (const Point &a, const Point &b){
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}
 
double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
double Cross(Vector A, Vector B){ return A.x*B.y - A.y*B.x; }

double dis(Point A,Point B){
	return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y);
}

//叉积极角排序
double compare(Point a,Point b,Point c){
	return Cross(c - a,c - b);//a在b顺时针 >0
}
bool cmp(Point a,Point b){
	if(dcmp(compare(a,b,C)) == 0) return dis(a,C) < dis(b,C);//短的在前
	return dcmp(compare(a,b,C)) > 0;
}

//Graham_scan凸包扫描 
void Graham_scan(Point p[]){
	int i,k = 0;
	Top = 2;
	for(i = 1;i < n; i++){
		if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
	}
	swap(p[0],p[k]);//p[0]是左下角点
	C = p[0];
	//按极角从小到大,距离偏短进行排序
	sort(p + 1,p + n,cmp);
	stack[0] = p[0];
	stack[1] = p[1];
	stack[2] = p[2];
	for(int i = 3;i < n; i++){
		while(Top > 1 && dcmp(compare(p[i],stack[Top],stack[Top - 1])) >= 0) Top--;
		stack[++Top] = p[i];
	} 
}

double get_S_Graham(){
	double ans = 0.0;
	for(int i = 1;i < Top;i++){
		ans += Cross(stack[i] - stack[0],stack[i + 1] - stack[0]);
	}
	ans /= 2.0;
	return ans;
}

poj1228 判断一个凸包是不是稳定凸包

感觉这个题数据有点水 稳定凸包共线的情况极角排序哪里似乎不太对?看了很多网上的代码也都一毛一样 

这里有一组数据可以参考一下:

9
0 0
1 0
2 0
2 1
2 2
0 2
0 1
1 3
0 4
 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
 
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int MaxN = 1e3 + 5;
 
int n,Top,t;
double L,Cir;
struct Point{
	double x,y;
	Point(double x = 0,double y = 0) : x(x),y(y) {}
}stack[MaxN],C,a[MaxN];
typedef Point Vector;
 
int dcmp(double x){//equal ?= 0
	if(fabs(x) < eps) return 0;
	else return x < 0 ? -1:1;
}
 
//运算符重载
Vector operator + (Vector A, Vector B){ return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Vector A, Vector B){ return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, double p){ return Vector(A.x*p, A.y*p); }
bool operator == (const Point &a, const Point &b){
	return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}
 
double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y; }
double Cross(Vector A, Vector B){ return A.x*B.y - A.y*B.x; }

double dis(Point A,Point B){
	return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y);
}

//叉积极角排序
double compare(Point a,Point b,Point c){
	return Cross(c - a,c - b);//a在b顺时针 >0
}
bool cmp(Point a,Point b){
	if(dcmp(compare(a,b,C)) == 0) return dis(a,C) < dis(b,C);//短的在前
	return dcmp(compare(a,b,C)) > 0;
}

//Graham_scan凸包扫描 
void Graham_scan(Point p[]){
	int i,k = 0;
	Top = 2;
	for(i = 1;i < n; i++){
		if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
	}
	swap(p[0],p[k]);//p[0]是左下角点
	C = p[0];
	//按极角从小到大,距离偏短进行排序
	sort(p + 1,p + n,cmp);
	stack[0] = p[0];
	stack[1] = p[1];
	stack[2] = p[2];
	for(int i = 3;i < n; i++){
		while(Top > 1 && compare(p[i],stack[Top],stack[Top - 1]) > 0) Top--;
		stack[++Top] = p[i];
	} 
}

bool convex_Stable(){
	stack[Top + 1] = stack[0];
	for(int i = 1;i < Top; i++){
		if(compare(stack[i + 1],stack[i],stack[i - 1]) && compare(stack[i + 2],stack[i + 1],stack[i])) return false;
	}
//	if(compare(stack[0],stack[Top],stack[Top - 1]) || compare(stack[0],stack[1],stack[2])) return 0;
	return true;
}
bool Collinear(){
	Point P = a[0];
	int cnt = 0,C = 0;
	for(int i = 1;i < n; i++){
		for(int j = i + 1;j < n; j++){
			double A = Cross(P - a[i],P - a[j]);
			C++;
			if(!dcmp(A)) cnt++;
		}
	}
	return C != cnt;
}

int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i = 0;i < n; i++){
			scanf("%lf %lf",&a[i].x,&a[i].y);
		}
		if(n < 6){
			printf("NO\n");
			continue;
		}
		Graham_scan(a);
		if(convex_Stable() && Collinear()) printf("YES\n");
		else printf("NO\n");
	}
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值