导弹发射
时间限制:1000 ms | 内存限制:65535 KB
难度:4
描述
Alpha 机构研发出一种新型智能导弹,它能够在雷达检测到的区域内,选择一条前进的路径, 击破路径上所有的目标物。 雷达位于(0,0)处,它能够检测到两条射线之间的区域(不妨设在第一象限)。 导弹一开始置放在(0,0)处,它可以在雷达能检测到的区域内先选择一个目标物击破,然后 再继续前进,选择另一个目标物击破。注意,导弹不能沿着这两条射线前进,当然也不能停在原 地。 可以假设,导弹一旦发射,其能量无比大,前进的路径无限长。 已知雷达能够检测到区域,其射线 1:ax-by=0 和射线 2:cx-dy=0。Alpha 机构的总指挥希望 在发现目标群的第一时刻,计算出一条可以击破最多目标物的路径。
输入
第一行: T 表示以下有 T 组测试数据(1≤T ≤8)
对每组测试数据:
第 1 行: n 表示目标物的个数
第 2 行: a b c d 代表两条射线的斜率分别是 a/b 和 c/d。
接下来有 n 行,每行 2 个正整数 xi yi 即第 i 个目标物的坐标。
【约束条件】
(1) n<=10^5 0<=a, b, c, d<=10^5 a 和 b 不会同时为 0,c 和 d 不会同时为 0;
(2) 0<= xi , yi <=10^6 i=1,…..,n
输出
每组测试数据,输出占一行,即导弹能击破的最多目标数。
样例输入
1
15
1 3 2 1
3 1
6 2
4 2
2 5
4 5
6 6
3 4
1 6
2 1
7 4
9 3
5 3
1 3
15 5
12 4
样例输出
4
本题刚开始就想错方向了开始认为是只要把射线夹着的点提取出来再找最大递增子序列即可,但是后来才发现原来射线内部和射线平行的两点也不行,所以还要进行一个判断,当时想着这样每次判断太复杂,但是也没更好的方法,就上网搜了一下,发现可以以两条射线为坐标轴重新定义坐标轴即可
代码:
#include<stdio.h> #include<string.h> #include<math.h> #include<string> #define INF 0x3fffffff #include<iostream> #include<algorithm> using namespace std; struct zb { double x,y; }s[100005]; bool cmp(zb a,zb b) { if(a.x==b.x) return a.y<b.y; else return a.x<b.x; } int erf(zb a,zb b[],int la,int lb)//注意二分,不二分会时间超限 { int zd; while(la<=lb) { zd=(la+lb)/2; if(a.y>b[zd].y) la=zd+1; else lb=zd-1; } return la; } int di(zb a[],int n)//求最长上升子序列 { int k=1; zb b[100005]; b[0]=a[0]; for(int i=1;i<n;i++) { if(a[i].x>b[k-1].x&&a[i].y>b[k-1].y) { b[k++]=a[i]; } else { int mi=erf(a[i],b,0,k); b[mi]=a[i]; } } return k; } int main() { int N; scanf("%d",&N); while(N--) { int m; int a,b,c,d; double s1; double s2; scanf("%d",&m); scanf("%d%d%d%d",&a,&b,&c,&d); s1=a*1.0/b; s2=c*1.0/d; if(s1>s2) { double r; r=s1; s1=s2; s2=r; } int t=0; for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); double ans=b*1.0/a; if(s1<ans&&s2>ans)//这个地方真的伤,开始是if(s1<b*1.0/a&&s2>b*1.0/a)总是错,还找不到错误,就找了网上代码,一点点改,都改的差不多一样了,还是错,最后发现就是这的问题,但不知道为啥,有大神可以帮忙解惑吗,求教 { s[t].x=a*1.0-b*1.0/s2; s[t].y=b*1.0-a*s1; t++; } } sort(s,s+t,cmp); int l=di(s,t); printf("%d\n",l); } }