HDU多校第一场 1013 Code —— 凸包相交

题目链接:点我啊╭(╯^╰)╮

题目大意:

     n n n 个三元组 ( x 1 , x 2 , y ) (x_1,x_2,y) x1,x2,y y ∈ { 1 , − 1 } y∈\{1,-1\} y{11}
     f ( x ) = w 1 × x 1 + w 2 × x 2 + w 0 f(x) = w_1\times x_1 + w_2\times x_2 + w_0 f(x)=w1×x1+w2×x2+w0
    问能否找到一组 ( w 1 , w 2 , w 0 ) (w_1,w_2,w_0) w1,w2,w0,使得 f ( x ) f(x) f(x) y = 1 y=1 y=1 > 0 >0 0 y = − 1 y=-1 y=1 < 0 <0 0

解题思路:

     f ( x ) = 0 f(x) = 0 f(x)=0 对应于二维平面上的一条直线
    当 y = 1 y=1 y=1 时在直线一侧, y = − 1 y=-1 y=1 时在另一侧
    则问题转化为能否找到一条直线,将这两类点分开
    等价于这两类点的凸包是否相交


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

核心:凸包问题转化

#include<bits/stdc++.h>
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const double eps = 1e-6;
const int maxn = 1e2 + 10;
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;
}

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;
}

// 判断线段 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");
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值