给出
n
n
n个横坐标从
1
1
1到
n
n
n,纵坐标为
0
0
0的点,以及
m
m
m个平面上的点,求从前面每个点任意角度作射线,问总共最多能覆盖到多少个点,点可以被重复覆盖。
注意到
m
m
m只有
250
250
250,直接考虑暴力枚举所有可能的斜率,然后对于每个斜率枚举所有点判断点是否在这条直线上。然后再判断这条直线落在
X
X
X轴是否是
1
−
n
1-n
1−n的整点。如果是则更新这个点的答案。
有一些小的细节,比如直线的斜率,以及精度的问题。复杂度是
O
(
n
3
)
O(n^3)
O(n3)的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=307;
const int M=1e6+3;
struct Point {
int x,y;
Point() {}
Point(int _x,int _y):x(_x),y(_y) {}
}p[N];
int ans[M];
bool check(Point a,Point b,Point c) {
return 1LL*(c.y-b.y)*(b.x-a.x)-1LL*(b.y-a.y)*(c.x-b.x)==0;
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d",&p[i].x,&p[i].y);
for(int i=1;i<=m;i++) {
for(int j=i+1;j<=m;j++) {
if(p[i].y==p[j].y) continue; // k=0
int in=0;
if(p[i].x==p[j].x) in=p[i].x;
else {
double k=(double)(p[i].y-p[j].y)/(double)(p[i].x-p[j].x);
double x,y;
if(p[i].y<p[j].y) {
x=(double)p[i].x;
y=(double)p[i].y;
}
else {
x=(double)p[j].x;
y=(double)p[j].y;
}
x-=y/k;
if(fabs(x-(int)(x+0.5))<=1e-8) {
in=(int)(x+0.5);
}
Point newx;
newx.x=in;
newx.y=0;
if(!check(newx,p[i],p[j]))
in=0;
}
if(in==0||in>n) continue;
int cnt=0;
for(int k=1;k<=m;k++) {
if(check(p[i],p[j],p[k])) ++cnt;
ans[in]=max(ans[in],cnt);
}
}
}
ll res=0;
for(int i=1;i<=n;i++)
res+=max(ans[i],1);
printf("%lld\n",res);
return 0;
}