hdu多校第一场 1013(hdu6590)Code 凸包交
Posted isakovsky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu多校第一场 1013(hdu6590)Code 凸包交相关的知识,希望对你有一定的参考价值。
题意:
给定一组(x1,x2,y),其中y为1或0,问是否有一组(w1,w2,b),使得上述的每一个(x1,x2,y)都满足x1*w1+x2*w2+b在y=1时大于0,在y=-1时小于0.
题解:
赛时想的是半平面交,wa到哭
后来看题解,居然那么简单?
我们把x1,x2看成两个坐标轴,那么其实(w1,w2,b)对应着一条直线,x1*w1+x2+w2+b=0,那么令这个值大于0的必定在这条直线一边,令这个值小于0的必定在这个直线另一边。这道题也就是在问,有没有一条线能分隔开这两种点。
那么把这两组点分别求出凸包,再去判断凸包有没有交就行了。注意,如果点在线上,那么上述式子算出来就得0了,因此两个凸包必须严格不交,点或边重合也不行。
代码:
//UVALive7461 - Separating Pebbles 判断两个凸包相交 #include <bits/stdc++.h> using namespace std; #define LL long long typedef pair<int,int> pii; const int inf = 0x3f3f3f3f; const int N =1e5+10; #define clc(a,b) memset(a,b,sizeof(a)) const double eps = 1e-8; const int MOD = 1e9+7; void fre() freopen("in.txt","r",stdin); void freout() freopen("out.txt","w",stdout); inline int read() int x=0,f=1;char ch=getchar();while(ch>‘9‘||ch<‘0‘) if(ch==‘-‘) f=-1;ch=getchar();while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘;ch=getchar();return x*f; int sgn(double x) if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1; struct Point int x,y; Point() Point(int _x,int _y) x = _x; y = _y; Point operator -(const Point &b)const return Point(x - b.x,y - b.y); int operator ^(const Point &b)const return x*b.y - y*b.x; int operator *(const Point &b)const return x*b.x + y*b.y; friend int dis2(Point a) return a.x*a.x+a.y*a.y; friend bool operator<(const Point &a,const Point &b) if(fabs(a.y-b.y)<eps) return a.x<b.x; return a.y<b.y; ; typedef Point Vector; double Dot(Point A, Point B)return A.x*B.x+A.y*B.y;//点积 double Cross(Vector A,Vector B)return A.x*B.y-A.y*B.x;//叉积 double Length(Vector A)return sqrt(Dot(A,A));//OA长 double Angle(Point A,Point B)return acos(Dot(A,B)/Length(A)/Length(B));//OA和OB的夹角 //判断线段相交,不在端点相交 bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2) double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1); return sgn(c1)*sgn(c2)<0&&sgn(c3)*sgn(c4)<0; int graham(Point p[],int n,Point q[]) int top=1; sort(p,p+n); if(n==0) return 0; q[0]=p[0]; if(n==1) return 1; q[1]=p[1]; if(n==2) return 2; q[2]=p[2]; for(int i=2;i<n;i++) while(top&&(Cross(q[top]-q[top-1],p[i]-q[top-1])<=0)) top--; q[++top]=p[i]; int len=top; q[++top]=p[n-2]; for(int i=n-3;i>=0;i--) while(top!=len&&(Cross(q[top]-q[top-1],p[i]-q[top-1])<=0)) top--; q[++top]=p[i]; return top; bool C_S(Point *ch1,int t1,Point *ch2,int t2)//判断凸包是否相交 double angle[1010],x; int i,j,k,m; if(t1==1)return true; if(t1==2) for(i=0;i<t2;i++) k=sgn(Cross(ch1[1]-ch1[0],ch2[i]-ch1[0])); if(k==0&&Dot(ch1[1]-ch1[0],ch2[i]-ch1[0])>0) if(Length(ch2[i]-ch1[0])<Length(ch1[1]-ch1[0]))break; if(i<t2)return false; if(t2==2&&SegmentProperIntersection(ch1[0],ch1[1],ch2[0],ch2[1]))return false; return true; angle[0]=0; for(i=2;i<t1;i++) angle[i-1]=Angle(ch1[1]-ch1[0],ch1[i]-ch1[0]); for(i=0;i<t2;i++) j=sgn(Cross(ch1[1]-ch1[0],ch2[i]-ch1[0])); if(j<0||(j==0&&Dot(ch1[1]-ch1[0],ch2[i]-ch1[0])<0))continue; j=sgn(Cross(ch1[t1-1]-ch1[0],ch2[i]-ch1[0])); if(j>0||(j==0&&Dot(ch1[t1-1]-ch1[0],ch2[i]-ch1[0])<0))continue; x=Angle(ch1[1]-ch1[0],ch2[i]-ch1[0]); m=lower_bound(angle,angle+t1-1,x)-angle; if(m==0)j=0; else j=m-1; k=sgn(Cross(ch1[j+1]-ch2[i],ch1[j+2]-ch2[i])); if(k>=0)break; if(i<t2)return false; return true; Point p1[300],p2[300],ch1[300],ch2[300]; int main() int T; scanf("%d",&T); while(T--) int n; scanf("%d",&n); int cnt1=0,cnt2=0; for(int i=0;i<n;i++) int x,y,c; scanf("%d%d%d",&x,&y,&c); if(c==0) p1[cnt1++]=Point(x,y); else p2[cnt2++]=Point(x,y); int t1=graham(p1,cnt1,ch1); int t2=graham(p2,cnt2,ch2); if(C_S(ch1,t1,ch2,t2)&&C_S(ch2,t2,ch1,t1)) printf("Successful!\n"); else printf("Infinite loop!\n");
以上是关于hdu多校第一场 1013(hdu6590)Code 凸包交的主要内容,如果未能解决你的问题,请参考以下文章