【题意概述】
给出平面上的10W个点,要求判断这些点能否被两条直线穿过,即一个点至少在一条直线上。
【题解】
思路很快可以想到。取3个不共线的点,它们形成一个三角形;如果有解,其中的一条直线一定与三角形的一条边重合。于是用这三条边一一进行验证即可。
第一次交被卡了精度,后来意识到判断三个点是否共线写丑了,其实并不需要求解析式。直接运用相似三角形,移项变成乘法即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define LL long long 5 #define rg register 6 #define N 200010 7 using namespace std; 8 int n; 9 bool v[N]; 10 struct rec{ 11 int x,y; 12 }p[N]; 13 inline int read(){ 14 int k=0,f=1; char c=getchar(); 15 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 16 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 17 return k*f; 18 } 19 inline bool cmp(rec a,rec b){ 20 return a.x==b.x?a.y<b.y:a.x<b.x; 21 } 22 inline bool ok(rec a,rec b){ 23 return a.x==b.x&&a.y==b.y; 24 } 25 inline void cal(rec a,rec b,rec &t){ 26 if(a.x<b.x) swap(a,b); 27 t.x=a.x-b.x; t.y=a.y-b.y; 28 } 29 inline bool judge(rec p1,rec p2,rec p3){ 30 rec t1,t2; 31 cal(p1,p2,t1); cal(p1,p3,t2); 32 return 1ll*t1.x*t2.y-1ll*t1.y*t2.x; 33 } 34 inline bool check(rec p1,rec p2){ 35 memset(v,0,sizeof(v)); 36 for(rg int i=1;i<=n;i++) if(!judge(p1,p2,p[i])) v[i]=1; 37 rec p3,p4; int cnt=0; 38 for(rg int i=1;i<=n;i++) if(!v[i]){ 39 if(!cnt) p3=p[i],cnt++; 40 else p4=p[i],cnt++; 41 } 42 if(cnt<=2) return 1; 43 for(rg int i=1;i<=n;i++) if((!v[i])&&(!judge(p3,p4,p[i]))) v[i]=1; 44 for(rg int i=1;i<=n;i++) if(!v[i]) return 0; 45 return 1; 46 } 47 int main(){ 48 n=read(); 49 if(n<=3){ 50 puts("YES"); return 0; 51 } 52 for(rg int i=1;i<=n;i++) p[i].x=read(),p[i].y=read(); 53 sort(p+1,p+1+n,cmp); 54 n=unique(p+1,p+1+n,ok)-p-1; 55 rec p1=p[1],p2=p[2],p3; 56 // for(rg int i=1;i<=n;i++) printf("[%d %d] ",p[i].x,p[i].y); puts(""); 57 for(rg int i=3;i<=n;i++) if(judge(p1,p2,p[i])){ 58 p3=p[i]; 59 break; 60 } 61 if(check(p1,p2)||check(p1,p3)||check(p2,p3)){ 62 puts("YES"); 63 return 0; 64 } 65 puts("NO"); 66 return 0; 67 }