大板子 —— 7

——— 计算几何 ———

—— 凸包 ——

Andrew:

int n;
struct point {
	double x, y;
	point(){}
	point(double X, double Y) { x = X, y = Y; }
	point operator - (const point &A) { return point(x-A.x, y-A.y); }
	bool operator < (const point &A)const {
		if(x == A.x) return y < A.y;
		return x < A.x;
	}
} a[maxn], pa[maxn];

int dcmp(double x){
	if(fabs(x) < eps) return 0;
	return x < 0 ? -1 : 1;
}
double cross(point a, point b) {	// 叉积
	return a.x*b.y - b.x*a.y;
}
double getd(point a, point b) {		// 两点距离
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

int andrew(point *P, int n, point *S) {	// P为点集合, A为凸包点
	sort(P, P+n);
	int tp = 0;
	for(int i=0; i<n; i++) {		// 下凸包 
		while(tp>1 && dcmp(cross(S[tp-1]-S[tp-2], P[i]-S[tp-2]))<=0) tp--;
		S[tp++] = P[i];
	}
	for(int i=n-2, k=tp; ~i; i--) {	// 上凸包 
		while(tp>k && dcmp(cross(S[tp-1]-S[tp-2], P[i]-S[tp-2]))<=0) tp--;
		S[tp++] = P[i];
	}
	return n > 1 ? tp - 1 : tp;
}

int main() {
    while(~scanf("%d", &n) && n){
		for(int i=0; i<n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
	    int tp = andrew(a, n, pa);
	    
		double ans = 0;
		for(int i=0; i<tp-1; i++) ans += getd(pa[i], pa[i+1]);
		ans += getd(pa[0], pa[tp-1]);
		if(n == 2) ans = getd(pa[0], pa[1]);
		printf("%.2f\n", ans);	
	}
}

Graham:

int tp, n;
struct point {
	double x, y;
	point(){}
	point(double X, double Y) { x = X, y = Y; }
	point operator - (const point &A) { return point(x-A.x, y-A.y); }
	bool operator < (const point &A)const {
		if(x == A.x) return y < A.y;
		return x < A.x;
	}
} a[maxn], pa[maxn];

int dcmp(double x){
	if(fabs(x) < eps) return 0;
	return x < 0 ? -1 : 1;
}
double cross(point a, point b) {	// 叉积
	return a.x*b.y - a.x*b.y;
}
double getd(point a, point b) {		// 两点距离
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
bool gcmp(point A, point B) {		// 极角排序 
	double tmp = cross(A-a[0], B-a[0]);
	if(dcmp(tmp) > 0) return true;
	if(dcmp(tmp)==0 && dcmp(getd(A,a[0])-getd(B,a[0]))<0) return true;
	return false;
} 

void graham(){
	sort(a+1, a+n, gcmp);
	tp = 0;
	for(int i=0; i<n; i++){
		while(tp>1 && dcmp(cross(pa[tp-1]-pa[tp-2], a[i]-pa[tp-2]))<=0) tp--;
		pa[tp++] = a[i];
	}
} 

int main() {
    while(~scanf("%d", &n) && n){
		for(int i=0; i<n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
		int p0 = 0;
		for(int i=1; i<n; i++) if(a[i] < a[p0]) p0 = i;
		swap(a[0], a[p0]); 
	    graham();
	    
		double ans = 0;
		for(int i=0; i<tp-1; i++) ans += getd(pa[i], pa[i+1]);
		ans += getd(pa[0], pa[tp-1]);
		if(n == 2) ans = getd(pa[0], pa[1]);
		printf("%.2f\n", ans);	
	}
}

凸包直径
int n;
struct point {
	double x, y;
	point() {}
	point(double X, double Y) { x = X, y = Y; }
	point operator - (const point &A) { return point(x-A.x, y-A.y); }
	bool operator < (const point &A)const {
		if(x == A.x) return y < A.y;
		return x < A.x;
	}
} a[maxn], pa[maxn];

double xmult(point a, point b, point c) {
	return cross(a-c, b-c);
}

int rotating_calipers(int tp) {
	int q = 1; double ret = 0;
//	pa[++tp] = pa[0];
	for(int i=0; i<tp; i++) {
		while(xmult(pa[i], pa[i+1], pa[(q+1)%tp]) > xmult(pa[i], pa[i+1], pa[q]))
			q = (q + 1) % tp;	
		ret = max(ret, getd2(pa[i], pa[q]));
//		ret = max(ret, max(getd2(pa[i], pa[q]), getd2(pa[i+1], pa[q])));
	}
	return ret;
}

int main() {
	scanf("%d", &n);
	for(int i=0; i<n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
	int tp = andrew(a, n, pa);
	printf("%d\n", rotating_calipers(tp));
}

最大三角形面积
int n;
struct point {
	double x, y;
	point(){}
	point(double X, double Y) { x = X, y = Y; }
	point operator - (const point &A) { return point(x-A.x, y-A.y); }
	bool operator < (const point &A)const {
		if(x == A.x) return y < A.y;
		return x < A.x;
	}
} a[maxn], pa[maxn];

double rotating_calipers(int tp){
	int p = 1, q = 2; double ret = 0;
//	pa[++tp] = pa[0];
	for(int i=0; i<tp; i++){
		while(xmult(pa[i], pa[p], pa[(q+1)%tp]) > xmult(pa[i], pa[p], pa[q]))
			q = (q + 1) % tp;	//	i,p 固定,旋转 q 
		ret = max(ret, xmult(pa[i], pa[p], pa[q]));
		while(xmult(pa[i], pa[(p+1)%tp], pa[q]) > xmult(pa[i], pa[p], pa[q]))
			p = (p + 1) % tp;	//	i,q 固定,旋转 p 
		ret = max(ret, xmult(pa[i], pa[p], pa[q]));
	}
	return ret;
}

int main() {
    while(~scanf("%d", &n) && n!=-1){
		for(int i=0; i<n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
	    int tp = andrew(a, n, pa);
		printf("%.2f\n", 0.5 * rotating_calipers(tp));	
	}
}

凸包相交

    判断凸包相交的两个必要条件:
     ① ① 一个凸包上的所有点不在另一个凸包内或边上
     ② ② 两个凸包没有线段相交

int cnt1, cnt2, k1, k2;
struct point {
	double x, y;
	point() {}
	point(double X, double Y) { x = X, y = Y; }
	point operator - (const point &A) { return point(x-A.x, y-A.y); }
	bool operator < (const point &A)const {
		if(x == A.x) return y < A.y;
		return x < A.x;
	}
} a[maxn], b[maxn], pa[maxn], pb[maxn];

inline int dcmp(double x) {
	if(fabs(x) < eps) return 0;
	return x < 0 ? -1 : 1;
}
inline double cross(point A, point B) {	//	叉积
	return A.x*B.y - B.x*A.y;
}
inline double dot(point A, point B) {	//	点积
	return A.x*B.x + B.y*A.y;
}

// 判断线段 AB是否跨立 MN
bool straddle(point A, point B, point M, point N) {
	point p0 = { N.x - M.x , N.y - M.y }; // 向量 MN
	point p1 = { A.x - M.x , A.y - M.y }; // 向量 MA
	point p2 = { B.x - M.x , B.y - M.y }; // 向量 MB
	return cross(p1, p0) * cross(p2, p0) <= 0;
}

// 判断 线段 AB为对角线构成的矩形 和 MN线段为对角线构成的矩形 是否存在重叠
bool overlap(point A, point B, point M, point N) {
	point P = { max(min(A.x, B.x), min(M.x, N.x)), max(min(A.y, B.y), min(M.y, N.y))};
	point Q = { min(max(A.x, B.x), max(M.x, N.x)), min(max(A.y, B.y), max(M.y, N.y))};
	return P.x <= Q.x && P.y <= Q.y;
}

// 判断线段 AB和 MN是否相交
bool intersect(point A, point B, point M, point N) {
	return straddle(A, B, M, N) && straddle(M, N, A, B) && overlap(A, B, M, N);
}

bool onsegment(point p, point A, point B) {
	return dcmp( cross(A-p, B-p) ) == 0 && dcmp( dot(A-p, B-p) ) < 0;
}

int ispip(point p, point poly[], int n) { // 判断点是否在多边形类
	int num = 0, k, d1, d2;
	for(int i=0; i<n; i++) {
		if(onsegment(p, poly[i], poly[(i+1)%n])) return -1; //	在边界上
		k = dcmp(cross(poly[(i+1)%n]-poly[i], p-poly[i]));
		d1 = dcmp(poly[i].y - p.y);
		d2 = dcmp(poly[(i+1)%n].y - p.y);
		if(k > 0 && d1 <= 0 && d2 > 0) num++;
		if(k < 0 && d2 <= 0 && d1 > 0) num++;
	}
	return num & 1;
}

bool check() {
	for(int i=0; i<k1; i++) if(ispip(pa[i], pb, k2) != 0) return false;
	for(int i=0; i<k2; i++) if(ispip(pb[i], pa, k1) != 0) return false;
	for(int i=0; i<k1; i++)
		for(int j=0; j<k2; j++)
			if(intersect(pa[i], pa[(i+1)%k1], pb[j], pb[(j+1)%k2]))
				return false;
	return true;
}

int main() {
	int T, n; scanf("%d", &T);
	while(T--) {
		scanf("%d", &n); cnt1 = 0, cnt2 = 0;
		for(int i=0; i<n; i++) {
			double x1, x2, y;
			scanf("%lf%lf%lf", &x1, &x2, &y);
			if(y < 0) a[cnt1++] = point {x1, x2};
			else b[cnt2++] = point {x1, x2};
		}
		k1 = andrew(a, cnt1, pa), k2 = andrew(b, cnt2, pb);
		printf(check() ? "Successful!\n" : "Infinite loop!\n");
	}
}

水平可见直线

给出若干直线 y = k x + b y=kx+b y=kx+b,当从上往下看时,求所有可见的直线
或者可以理解为一堆直线里 最上面的的那些直线


发现这些直线是下凸的,并且斜率递增
n a m o namo namo求个下凸包即可,按照 k k k 从小到大, b b b 从大到小的顺序 排序
设栈顶的两条直线为 q [ t a i l − 1 ] q[tail-1] q[tail1] q [ t a i l ] q[tail] q[tail],当前直线为 l [ i ] l[i] l[i]
q [ t a i l − 1 ] q[tail-1] q[tail1] q [ t a i l ] q[tail] q[tail] 的交点为 x 1 x_1 x1 q [ t a i l ] q[tail] q[tail] l [ i ] l[i] l[i] 的交点为 x 2 x_2 x2
x 1 > = x 2 x_1 >= x_2 x1>=x2,则可以弹栈了

特殊的,当斜率相等时,肯定截距越大越好
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
在这里插入图片描述

int n;
struct Line{
	int k, b, id;
	bool operator < (const Line &A) const {
		return k==A.k ? b>A.b : k<A.k;
	}
} l[maxn], q[maxn];

double find(Line x, Line y){
	return 1.0 * (y.b - x.b) / (x.k - y.k);
}

signed main() {
	scanf("%d", &n);
	for(int i=1; i<=n; i++) scanf("%d%d", &l[i].k, &l[i].b), l[i].id = i;
	sort(l+1, l+1+n);
	int tail = 0;
	for(int i=1; i<=n; i++){
		if(l[i].k == l[i-1].k && i != 1) continue;
		while(tail>1 && find(l[i], q[tail])<=find(q[tail-1], q[tail])) tail--;
		q[++tail] = l[i];
	}
	vector <int> ans;
	for(int i=1; i<=tail; i++) ans.push_back(q[i].id);
	sort(ans.begin(), ans.end());
	for(auto i : ans) printf("%d ", i);
}

—— 几何 ——
三点求圆、求三角形面积

附eps用法:

a = = b a == b a==b f a b s ( a − b ) < e p s fabs(a-b) < eps fabs(ab)<eps
a ! = b a != b a!=b f a b s ( a − b ) > e p s fabs(a-b) > eps fabs(ab)>eps
a < b a < b a<b a − b < − e p s a - b < -eps ab<eps
a < = b a <= b a<=b a − b < e p s a - b < eps ab<eps
a > b a > b a>b a − b > e p s a - b > eps ab>eps
a > = b a >= b a>=b a − b > − e p s a - b > -eps ab>eps

struct point {
	double x, y;
	friend point operator - (point a, point b) {
		point tmp;
		tmp.x = a.x - b.x;
		tmp.y = a.y - b.y;
		return tmp;
	}
};

point get_pc(point p1, point p2, point p3) {	// 求圆心
	double a, b, c, d, e, f, r; point p;
	a = 2*(p2.x-p1.x); b = 2*(p2.y-p1.y);
	c = p2.x*p2.x + p2.y*p2.y - p1.x*p1.x - p1.y*p1.y;
	d = 2*(p3.x-p2.x); e = 2*(p3.y-p2.y);
	f = p3.x*p3.x + p3.y*p3.y - p2.x*p2.x - p2.y*p2.y;
	p.x = (b*f-e*c) / (b*d-e*a); p.y = (d*c-a*f) / (b*d-e*a);
	r = sqrt((p.x-p1.x)*(p.x-p1.x) + (p.y-p1.y)*(p.y-p1.y));	//	半径
	return p;
}

double getdis(point a, point b) {	// 两点距离
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

double gets1(point a, point b, point c) {	// 叉积求面积
	return fabs((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x))/2.0;
}

double gets2(double a, double b, double c) {	// 三边求面积
	double p = (a + b + c) / 2.0;
	return sqrt(p * (p-a) * (p-b) * (p-c));
}

最近线段距离

    暴力枚举每两条线段的距离
    但要对每条线段的左端点排序
    若左侧线段的右端点 x x x 与右侧线段的左端点 x x x 差值大于了 a n s ans ans
    则直接 b r e a k break break,这样竟然能优化 19 19 19

struct point {
	double x, y;
	point() {}
	point(double X, double Y) { x = X, y = Y; }
	point operator - (const point &A) { return point(x-A.x, y-A.y); }
	bool operator < (const point &A)const {
		if(x == A.x) return y < A.y;
		return x < A.x;
	}
} ;

inline int dcmp(double x) {
	if(fabs(x) < eps) return 0;
	return x < 0 ? -1 : 1;
}
inline double cross(point A, point B) {	//	叉积
	return A.x*B.y - B.x*A.y;
}
inline double dot(point A, point B) {	//	点积
	return A.x*B.x + B.y*A.y;
}

double getdis(point a, point b) {	//	两点距离
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

struct Line {
	point s, e;
	Line() {}
	Line(point S, point E) { s = S, e = E; }
	double length() { return getdis(s, e); }
};

//点到直线距离
inline double point_to_line(point p, Line a) {
	return fabs(cross(p-a.s, a.e-a.s) / a.length());
}

//点到线段距离
inline double point_to_seg(point p, Line a) {
	if(dcmp(dot(p-a.s, a.e-a.s))<0 || dcmp(dot(p-a.e, a.s-a.e))<0)
		return min(getdis(p, a.e), getdis(p, a.s));
	return point_to_line(p, a);
}

//线段到线段的距离
inline double seg_to_seg(Line u, Line v) {
	return min( min(point_to_seg(u.s, v), point_to_seg(u.e, v)),\
	        min( point_to_seg(v.s, u), point_to_seg(v.e, u)) );
}

bool cmp(const Line &u, const Line &v) {
	return u.s < v.s;
}

const int maxn = 1e4 + 5;
int T, n;
Line line[maxn];
int main() {
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		for(int i=1; i<=n; i++) {
			scanf("%lf%lf", &line[i].s.x, &line[i].s.y);
			scanf("%lf%lf", &line[i].e.x, &line[i].e.y);
			if(line[i].e < line[i].s) swap(line[i].s, line[i].e);
		}
		sort(line+1, line+1+n, cmp);
		double ans = 1e10;
		for(int i=1; i<=n; i++) {
			for(int j=i+1; j<=n; j++) {
				if(dcmp(line[j].s.x-line[i].e.x - ans) > 0) break;
				ans = min(ans, seg_to_seg(line[i], line[j]));
			}
		}
		printf("%.9f\n", ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值