G49 向量运算 点线关系
视频链接:https://www.bilibili.com/video/BV1yY4y1C7PZ/
题意:给你一个点的坐标和半径,然后给平面上的点集S,求以这个点为圆心的半圆最多能覆盖S中的点的个数
思路:
1. 先预处理,仅保留圆内的点
2. 最优解一定可以保证至少有一个点在直径上,枚举每个可能在直径上的点,从而枚举出有用的角度
3. 对于每个角度,可以暴力找出所有在这条直径左侧的点,更新答案。用叉积判断点线的位置关系
时间:O(n*n*T)
#include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N=155; struct Point{int x,y;} p[N],o,a; double cross(Point a,Point b,Point c){ //叉积 return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); } double dis(Point a,Point b){ //距离 return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int main(){ int n,m,ans; double r; while(scanf("%d%d%lf",&o.x,&o.y,&r),r>=0){ n = ans = 0; scanf("%d",&m); while(m--){ scanf("%d%d",&a.x,&a.y); if(dis(a,o)<=r) p[n++]=a; } for(int i=0;i<n;i++){ int cnt=0; for(int j=0;j<n;j++) if(cross(o,p[i],p[j])>=0) ++cnt; ans=max(ans,cnt); } printf("%d\n",ans); } return 0; }
2. POJ2318 TOYS
题意:n 块纸板将一个盒子分成 n+1 部分,给你 m 个玩具的坐标,求这 n+1 部分中每一部分包含多少个玩具
思路:给的纸板的坐标是排好序的,可以二分查找每个玩具的分区,用叉积判断玩具的位置
时间:O(m*logn*10)
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N=5010; struct Point{long long x,y;} a[N],b[N],p; int n,m,ans[N]; long long cross(Point a,Point b,Point c){ //叉积 return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x); } int find(Point p){ //二分 int l=-1,r=n+1; while(l+1<r){ int mid=l+r>>1; if(cross(b[mid],a[mid],p)<=0) l=mid; else r=mid; } return l; } int main(){ long long x1,y1,x2,y2, u,l; bool num1=1; while(scanf("%d",&n),n){ scanf("%d%lld%lld%lld%lld",&m,&x1,&y1,&x2,&y2); a[0].x=x1,a[0].y=y1;b[0].x=x1,b[0].y=y2;//左边界 for(int i=1; i<=n; i++){ scanf("%lld%lld",&u,&l); a[i].x=u,a[i].y=y1;b[i].x=l,b[i].y=y2;//纸板端点 } memset(ans,0,sizeof ans); while(m--){ scanf("%lld%lld",&p.x,&p.y); //玩具坐标 ans[find(p)]++; //二分答案 } num1 ? num1=0 : puts(""); //第一行不输出空行 for(int i=0;i<=n;i++)printf("%d: %d\n",i,ans[i]); } return 0; }