【模板】凸包

如图是一个凸包。

graph LR; A((a))---B((b))---C((c))---D((d)) A---E((e))---D

现在有了\(f\)的出现,原来的图形不再是凸包,那么如何判断\(f\)一类的点呢。

graph LR; A((a))---B((b))---F((f))---D((d)) B---C((c))---D A---E((e))---D C---F

那我们每次加点时判断新加的点与上一个点构成的向量是否左拐。
若左拐,则可知此点是类于\(f\)的点,那把上一个点\(c\)删掉就是了。

#include <stdio.h>
#include <cmath>
#include <algorithm>
const int z = 1e6+10;
const double pi = 3.1415926;
using namespace std;
struct VECTOR {
	double x, y;
	VECTOR (double a,double b) {x = a, y = b;}
	double operator ^ (const VECTOR object) {
		return x*object.y-y*object.x;
	}
};
struct NODE {
	double x, y;
	bool operator < (const NODE object) {
		if(x == object.x) 
			return y < object.y;
		return x < object.x;
	}
	VECTOR operator - (const NODE object) {
		return VECTOR(x-object.x,y-object.y);
	}
} node[z];
int stk[z], top;
void Andrew(int n) {
	sort(node+1,node+1+n);
	if(n < 3) 
		return;
	stk[++top] = 1, stk[++top] = 2;
	for(int i = 3;i <= n;++i) {
		VECTOR u = node[stk[top]]-node[stk[top-1]];
		VECTOR v = node[i]-node[stk[top]];
		while(top > 1&&(u^v) < 0) {
			top--;
			u = node[stk[top]]-node[stk[top-1]];
			v = node[i]-node[stk[top]];
		}
		stk[++top] = i;
	}
	int tmp = top;
	stk[++top] = n-1;
	for(int i = n-2;i >= 1;--i) {
		VECTOR u = node[stk[top]]-node[stk[top-1]];
		VECTOR v = node[i]-node[stk[top]];
		while(top > tmp&&(u^v) < 0) {
			top--;
			u = node[stk[top]]-node[stk[top-1]];
			v = node[i]-node[stk[top]];
		}
		stk[++top] = i;
	}
}
int n;
double ans;
double L;
double fq(double a) {
	return a*a;
}
void work() {
	scanf("%d %lf",&n,&L);
	for(int i = 1;i <= n;++i) 
		scanf("%lf %lf",&node[i].x,&node[i].y);
	Andrew(n);
	for(int i = 1;i < top;++i) {
		ans += sqrt(fq(node[stk[i]].x-node[stk[i+1]].x)+fq(node[stk[i]].y-node[stk[i+1]].y));
	}
	ans += 2*L*pi;
	printf("%.0lf",ans);
}
signed main() {
	work();
}

动态凸包

我们要求不断地往里插入,并查询某一点是否在凸包中。

#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <set>
const int z = 1e6+10;
using namespace std;
struct VECTOR {
	double x, y;
	VECTOR () {x = y = 0;}
	VECTOR (double _a,double _b) {x = _a, y = _b;}
} node[4];
double operator ^ (const VECTOR &subject,const VECTOR &object) {
	return subject.x*object.y-subject.y*object.x;
}
VECTOR operator - (const VECTOR &subject,const VECTOR &object) {
	return VECTOR(subject.x-object.x,subject.y-object.y);
}
VECTOR operator + (const VECTOR &subject,const VECTOR &object) {
	return VECTOR(subject.x+object.x,subject.y+object.y);
}
bool operator < (const VECTOR &_x,const VECTOR &_y) {
	if(_x.x == _y.x) 
		return _x.y < _y.y;
	return _x.x < _y.x;
}
multiset<VECTOR> up, dn;
bool Isindownhull(const VECTOR &object) {
	if(dn.count(object) > 0) 
		return true;
	std :: multiset<VECTOR> :: iterator it1, it2;
	it1 = it2 = dn.upper_bound(object);
	if(it1 == dn.begin()) 
		return false;
	if(it1 == dn.end()) 
		return false;
	it2--;
	if((((*it2)-object)^((*it1)-object)) >= 0&&(((*dn.begin())-object)^((*--dn.end())-object)) <= 0) 
		return true;
	else 
		return false;
}
bool Isinuphull(const VECTOR &object) {
	if(up.count(object) > 0) 
		return true;
	std :: multiset<VECTOR> :: iterator it1, it2;
	it1 = it2 = up.upper_bound(object);
	if(it1 == up.begin()) 
		return false;
	if(it1 == up.end()) 
		return false;
	it2--;
	if((((*it2)-object)^((*it1)-object)) <= 0&&(((*--up.end())-object)^((*up.begin())-object)) <= 0) 
		return true;
	else 
		return false;
}
bool DOWNH(const VECTOR &object) {
	if(dn.count(object) > 0) 
		return true;
	multiset<VECTOR> :: iterator it1, it2;
	it1 = it2 = dn.upper_bound(object);
	if(it1 == dn.begin()) 
		return false;
	if(it1 == dn.end()) 
		return false;
	it2--;
	if((((*it2)-object)^((*it1)-object)) >= 0) 
		return true;
	else 
		return false;
}
bool UPH(const VECTOR &object) {
	if(up.count(object) > 0) 
		return true;
	std :: multiset<VECTOR> :: iterator it1, it2;
	it1 = it2 = up.upper_bound(object);
	if(it1 == up.begin()) 
		return false;
	if(it1 == up.end()) 
		return false;
	it2--;
	if((((*it2)-object)^((*it1)-object)) <= 0) 
		return true;
	else 
		return false;
}
multiset<VECTOR> :: iterator Pre(multiset<VECTOR> &s,const VECTOR &object) {
	multiset<VECTOR> :: iterator it;
	it = s.lower_bound(object);
	if(it == s.begin()) 
		return s.end();
	it--;
	return it;
}
multiset<VECTOR> :: iterator Suc(multiset<VECTOR> &s,const VECTOR &object) {
	multiset<VECTOR> :: iterator it;
	it = s.upper_bound(object);
	return it;
}
void Insert(const VECTOR &object) {
	bool tmp2 = UPH(object);
	bool tmp1 = DOWNH(object);
	if(tmp1&&tmp2) 
		return;
	std :: multiset<VECTOR> :: iterator it1, it2;
	if(!tmp1) {
		while(1) {
			it1 = Suc(dn,object);
			if(it1 == dn.end()) break;
			it2 = Suc(dn,*it1);
			if(it2 == dn.end()) break;
			if((((*it1)-object)^((*it2)-object)) <= 0) 
				dn.erase(*it1);
			else 
				break;
		}
		while(1) {
			it1 = Pre(dn,object);
			if(it1 == dn.end()) break;
			it2 = Pre(dn,*it1);
			if(it2 == dn.end()) break;
			if((((*it1)-object)^((*it2)-object)) >= 0) 
				dn.erase(*it1);
			else 
				break;
		}
		dn.insert(object);
	}
	if(!tmp2) {
		while(1) {
			it1 = Suc(up,object);
			if(it1 == up.end()) break;
			it2 = Suc(up,*it1);
			if(it2 == up.end()) break;
			if((((*it1)-object)^((*it2)-object)) >= 0) {
				up.erase(*it1);
			} else break;
		}
		while(1) {
			it1 = Pre(up,object);
			if(it1 == up.end()) break;
			it2 = Pre(up,*it1);
			if(it2 == up.end()) break;
			if((((*it1)-object)^((*it2)-object)) <= 0) {
				up.erase(*it1);
			} else break;
		}
		up.insert(object);
	}
}
int n;
void work() {
	scanf("%d",&n);
	for(int i = 1;i <= 3;++i) {
		int opt;
		scanf("%d %lf %lf",&opt,&node[i-1].x,&node[i-1].y);
	}
	sort(node,node+3);
	up.insert(node[0]), up.insert(node[2]);
	dn.insert(node[0]), dn.insert(node[2]);
	if(((node[1]-node[0])^(node[2]-node[0])) > 0) {
		dn.insert(node[1]);
		printf("dn\n");
	}
	else 
		up.insert(node[1]);
	for(int i = 4;i <= n;++i) {
		double a, b;
		int opt;
		scanf("%d %lf %lf",&opt,&a,&b);
		if(opt == 1) {
			Insert(VECTOR{a,b});
		} else {
			printf("%d\n",(int)(UPH(VECTOR{a,b})&&DOWNH(VECTOR{a,b})));
		}
	}
}
signed main() {
	work();
}

@bikuhiku

posted @ 2022-06-06 21:33  bikuhiku  阅读(21)  评论(0编辑  收藏  举报