凸包问题

POJ 3348 :http://poj.org/problem?id=3348

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int N = 10005;

struct point {
	double x,y;
	point() {}
	point(double _x,double _y):
		x(_x),y(_y) {}
	friend point operator - (const point &a,const point &b) {
		return point(a.x-b.x,a.y-b.y);
	}
	friend double operator * (const point &a,const point &b) { 
		return a.x*b.y-a.y*b.x;
	}
	double dis() {
		return x*x+y*y;
	}
} p[N],ans[N];
int n,m;

bool cmp(point a,point b) { //极角排序另一种方法,精度高 
	double xx=p[1].x,yy=p[1].y;
	point p0=point {xx,yy};
	a=a-p0;
	b=b-p0;
	if(a*b!=0)
		return a*b>0;
	return a.x<b.x;
}
bool cmp1(point a,point b){//极角排序另一种方法,速度快
	double xx=p[1].x,yy=p[1].y;
    if(atan2(a.y-yy,a.x-xx)!=atan2(b.y-yy,b.x-xx))
        return (atan2(a.y-yy,a.x-xx))<(atan2(b.y-yy,b.x-xx));
    return a.x<b.x;
}

void graham() { 
	int id=1;
	m=0;
	for(int i=2; i<=n; i++)
		if(p[i].x<p[id].x||(p[i].x==p[id].x&&p[i].y<p[id].y))
			id=i;
	if(id!=1) 
		swap(p[1],p[id]);
	//寻找最左下的点 
	sort(p+2,p+n+1,cmp);
	//极角排序 
	ans[++m]=p[1];
	for(int i=2; i<=n; i++) {
		//遍历每一个点,如果当前点形成凹多边形,即弹出
		while(m>=2 && (ans[m]-ans[m-1])*(p[i]-ans[m])<=0) m--; 
		ans[++m]=p[i];
	}
}

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;++i) {
		scanf("%lf%lf",&p[i].x,&p[i].y);
	}
	if(n == 2 or n == 1) {
		printf("0\n");
		return 0;
	}
	graham();
	double Ans=0;
	for(int i=2;i<m;i++)
    	Ans+=(ans[i]-ans[1])*(ans[i+1]-ans[1]);
	printf("%d\n",int(Ans/100));
	return 0;
}

 

HDU 1392 :http://acm.hdu.edu.cn/showproblem.php?pid=1392

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int N = 10005;

struct point {
	double x,y;
	point() {}
	point(double _x,double _y):
		x(_x),y(_y) {}
	friend point operator - (const point &a,const point &b) {
		return point(a.x-b.x,a.y-b.y);
	}
	friend double operator * (const point &a,const point &b) { 
		return a.x*b.y-a.y*b.x;
	}
	double dis() {
		return x*x+y*y;
	}
} p[N],ans[N];
int n,m;

bool cmp(point a,point b) { //极角排序另一种方法,精度高 
	double xx=p[1].x,yy=p[1].y;
	point p0=point {xx,yy};
	a=a-p0;
	b=b-p0;
	if(a*b!=0)
		return a*b>0;
	return a.x<b.x;
}
bool cmp1(point a,point b){//极角排序另一种方法,速度快
	double xx=p[1].x,yy=p[1].y;
    if(atan2(a.y-yy,a.x-xx)!=atan2(b.y-yy,b.x-xx))
        return (atan2(a.y-yy,a.x-xx))<(atan2(b.y-yy,b.x-xx));
    return a.x<b.x;
}

void graham() { 
	int id=1;
	m=0;
	for(int i=2; i<=n; i++)
		if(p[i].x<p[id].x||(p[i].x==p[id].x&&p[i].y<p[id].y))
			id=i;
	if(id!=1) 
		swap(p[1],p[id]);
	//寻找最左下的点 
	sort(p+2,p+n+1,cmp);
	//极角排序 
	ans[++m]=p[1];
	for(int i=2; i<=n; i++) {
		//遍历每一个点,如果当前点形成凹多边形,即弹出
		while(m>=2 && (ans[m]-ans[m-1])*(p[i]-ans[m])<=0) m--; 
		ans[++m]=p[i];
	}
}

double Dis(point a,point b) {
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main() {
	while(~scanf("%d",&n) and n!=0) {
		for(int i=1; i<=n; ++i) {
			scanf("%lf%lf",&p[i].x,&p[i].y);
		}

		if(n == 2) {
			printf("%.2lf\n",Dis(p[1],p[2]));
			continue;
		}
		graham();

		double Ans=0;
		ans[m+1]=ans[1];//cout<<m<<endl;
		for(int i=1; i<=m; ++i)
			Ans+=Dis(ans[i],ans[i+1]);
		printf("%.2lf\n",Ans);
	}
	return 0;
}

POJ 1228 :http://poj.org/problem?id=1228

这个题求的是一个稳定凸包,网上一堆人说要求共线凸包,就是所有在凸包边上的点都存在ans数组里面,我多次尝试无果

然后用他们的代码测试,发现他们的代码也无法完成,题中样例都无法过去,于是还是用了原来的板子求了纯净凸包,然后O(n²)过的

然而这些所谓共线凸包的代码,并不能通过所有点在一条直线上的样例

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
typedef long long LL;
const int N = 1010;

struct point {
	double x,y;
	point() {}
	point(double _x,double _y):
		x(_x),y(_y) {}
	friend point operator - (const point &a,const point &b) {
		return point(a.x-b.x,a.y-b.y);
	}
	friend double operator * (const point &a,const point &b) {
		return a.x*b.y-a.y*b.x;
	}
	double dis() {
		return x*x+y*y;
	}
} p[N],ans[N];
int n,m;
double dis(point a, point b) {
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
bool cmp(point a,point b) { //极角排序另一种方法,精度高
	double xx=p[1].x,yy=p[1].y;
	point p0=point {xx,yy};
	a=a-p0;
	b=b-p0;
	if(a*b!=0)
		return a*b>0;
	return a.x<b.x;
}
bool cmp1(point a,point b) { //极角排序另一种方法,速度快
	double xx=p[1].x,yy=p[1].y;
	if(atan2(a.y-yy,a.x-xx)!=atan2(b.y-yy,b.x-xx))
		return (atan2(a.y-yy,a.x-xx))<(atan2(b.y-yy,b.x-xx));
	return a.x<b.x;
}


void graham() {
	int id=1;
	m=0;
	for(int i=2; i<=n; i++)
		if(p[i].x<p[id].x||(p[i].x==p[id].x&&p[i].y<p[id].y))
			id=i;
	if(id!=1)
		swap(p[1],p[id]);
	//寻找最左下的点
	sort(p+2,p+n+1,cmp);
	//极角排序
	ans[++m]=p[1];//cout<<p[1].x<<" "<<p[1].y<<endl;
	for(int i=2; i<=n; i++) {//cout<<p[i].x<<" "<<p[i].y<<endl;
		//遍历每一个点,如果当前点形成凹多边形,即弹出
		while(m>=2 && (p[i]-ans[m])*(ans[m-1]-ans[m])<=0) m--;
		
		ans[++m]=p[i];//cout<<m<<endl;
	}
}

double multi(point p1, point p2, point p3) {
	return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
}
int main() {
	int t;
	scanf("%d",&t);
	while(t--) {
		scanf("%d",&n);
		for(int i=1; i<=n; i++) {
			scanf("%lf%lf",&p[i].x,&p[i].y);
		}
		graham();
		ans[m+1]=ans[1];
		int flag=0;
		for(int i=1; i<=m; i++) {
			int sum=0;
			for(int j=1; j<=n; j++) {
				if(( (p[j]-ans[i+1]) * (ans[i]-ans[i+1]) )==0)
					sum++;
			}
			if(sum<3) {
				flag=1;
				break;
			}
		}
		if(flag==0 && m>=3)
			printf("YES\n");
		else
			printf("NO\n");
	}

	return 0;
}

判断点是否在多边形内部:

bool onsegment(point pi,point pj,point Q) {
	if((Q.x-pi.x)*(pj.y-pi.y)==(pj.x-pi.x)*(Q.y-pi.y)&&min(pi.x,pj.x)<=Q.x&&Q.x<=max(pi.x,pj.x)&&min(pi.y,pj.y)<=Q.y&&Q.y<=max(pi.y,pj.y)) {
		return true;
	} else {
		return false;
	}
}

bool insidepolygon(point pp) {
	int counter=0;
	double xinters;
	point p1,p2;
	p1=p[1];
	for(int i=2; i<=n+1; i++) {
		p2=p[i%(n+1)];
		if(onsegment(p1,p2,pp)) {
			return true;
		}
		if(pp.y>min(p1.y,p2.y)) {
			if(pp.y<=max(p1.y,p2.y)) {
				if(pp.x<=max(p1.x,p2.x)) {
					if(p1.y!=p2.y) {
						xinters=(pp.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x;
						if(p1.x==p2.x||pp.x<=xinters) {
							counter++;
						}
					}
				}
			}
		}
		p1=p2;
	}
	if(counter%2==0) {
		return false;
	}
	return true;
}

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值