题意:
给定一组(x1,x2,y),其中y为1或0,问是否有一组(w1,w2,b),使得上述的每一个(x1,x2,y)都满足x1*w1+x2*w2+b在y=1时大于0,在y=-1时小于0.
题解:我们可以将(x1,x2)看成是坐标点,那么题目就可看成,能否找出一条直线,将1点与-1点分开。
也就是我们可以求1点的凸包以及-1点的凸包。然后我们再判断这两个凸包是否相交。假如不相交,说明存在这样一条直线。
对于求两凸包是否相交,我们可以判断一个凸包上的点是否在另一个凸包里面,假设都不在,说明这两凸包不相交。
判断点是否在凸包里面,我们可以二分,找到一条线段,使得该点被夹在这条线段之间,那么此时如果该点在这条线段的左边,说明该点在该凸包里面。
#include<bits/stdc++.h>
using namespace std;
const int N=105;
typedef long long LL;
struct point{
LL x,y;
point(){}
point(LL _x,LL _y){
x=_x;y=_y;
}
}date[2][N],aim[2][N];
point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,int p) { return point(a.x*p,a.y*p);}
bool operator < (const point &a,const point &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
if(fabs(x)<esp) return 0;
else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
LL Cross(point a,point b) { return a.x*b.y-a.y*b.x;}
double Length(point a) { return sqrt(a.x*a.x*1.0+a.y*a.y*1.0);}
bool cmp(point a,point b) ///坐标排序
{
return (a.y<b.y||(a.y==b.y&&a.x<b.x));
}
int andrew(point *p,int n,point *ch)
{
sort(p,p+n,cmp);
int tot=-1;
for(int i=0;i<n;i++) ///构造凸包下侧
{
while(tot>0&&Cross(ch[tot]-ch[tot-1],p[i]-ch[tot-1])<=0)
tot--;
ch[++tot]=p[i];
}
for(int i=n-2,k=tot;i>=0;i--){ ///构造凸包上侧
while(tot>k&&Cross(ch[tot]-ch[tot-1],p[i]-ch[tot-1])<=0)
tot--;
ch[++tot]=p[i];
}
///区间在[0,tot],ch[0]=ch[tot];
return tot;
}
///二分判断点A是否在凸包p中
bool check(point A,point *p,int n)
{
///r=n-1,因为0点与n点是同样的点
int l=0,r=n-1,mid;
while(l<=r)
{
mid=(l+r)>>1;
LL a1=Cross(p[mid]-p[0],A-p[0]);
LL a2=Cross(p[mid+1]-p[0],A-p[0]);
if(a1>=0&&a2<=0)
{
///当某个点被夹在线段mid-(mid+1)之间,假如点在向量mid-(mid+1)左边
///说明该点在该凸包里
if(Cross(p[mid+1]-p[mid],A-p[mid])>=0) return true;
return false;
}
///往下找,能到这一步,说明p[mid],p[mid+1]都在点A上面、
///因为我们需要一正一负,故要往下找
else if(a1<0)
r=mid-1;
else l=mid+1; ///往上找,能到这一步,说明p[mid],p[mid+1]都在点A下面
}
return false;
}
int main()
{
int ncase;
scanf("%d",&ncase);
int num0[2],num1[2];
while(ncase--)
{
///num1存储1点,num0存储-1点
num0[0]=num0[1]=num1[0]=num1[1]=0;
memset(date,0,sizeof(date));
memset(aim,0,sizeof(aim));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
LL x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
if(z==1) date[1][num1[0]++]=point(x,y);
else date[0][num0[0]++]=point(x,y);
}
///分别给1点和-1点求凸包
num0[1]=andrew(date[0],num0[0],aim[0]);
num1[1]=andrew(date[1],num1[0],aim[1]);
// }
bool flag=false;
///检查凸包-1点,此点是否在凸包1点中
for(int i=0;i<num0[1];i++)
flag|=check(aim[0][i],aim[1],num1[1]);
///检查凸包1点,此点是否在凸包-1点中
for(int i=0;i<num1[1];i++)
flag|=check(aim[1][i],aim[0],num0[1]);
if(!flag) puts("Successful!");
else puts("Infinite loop!");
}
return 0;
}