题目链接:点我啊╭(╯^╰)╮
题目大意:
n
n
n 个三元组
(
x
1
,
x
2
,
y
)
(x_1,x_2,y)
(x1,x2,y),
y
∈
{
1
,
−
1
}
y∈\{1,-1\}
y∈{1,−1}
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");
}
}