第九届河南省程序设计大赛
D 导弹发射
内存限制:64MB 时间限制:1s Special Judge: No
题目描述:
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
这道题花费的时间还是挺多的,有几点需要注意,我被坑了好久
我的思路是首先通过两个射线过滤不符合要求的,然后按照x的值从小到大排序,若想等就按照y的值从小到大排序
然后再在y的序列中寻找最大上升子序列就行了。但是试了很多次都是wa,后来看看大神的博客才知道就算在射线内的两点,两点之间的连线斜率也不可以同两条射线相同(这个很坑,样例中看不出有这个要求,题意描述更是看不出来有这个要求)
后来依照两条射线重新建立坐标轴就可以了,
代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
double y;
double x;
}qu1[100500];
bool cmp(node x1,node y1)//定义排序顺序
{
if(x1.x==y1.x)
return x1.y<y1.y;
return x1.x<y1.x;
}
int main()
{
int n,t;
int u,w;
double a,b,c,d;
int sum=0;
cin>>t;
while(t--)
{
cin>>n;
cin>>a>>b>>c>>d;
double k1=(a/b)>(c/d)?(a/b):(c/d);
double k2=(a/b)>(c/d)?(c/d):(a/b);
qu1[0].x=0;
qu1[0].y=0;
int j=0;
for(int i=0;i<n;i++){
cin>>u>>w;
double ans=(w*1.0)/(u*1.0);
if(ans>k2&&ans<k1)//在两条射线内
{
qu1[j].x=u*1.0-w*1.0/k1;//重新建立坐标轴
qu1[j].y=w*1.0-u*k2;
j++;
}
}
sort(qu1,qu1+j,cmp);
double y1[100500]={0};
double y2[100500]={0};
for(int i=0;i<j;i++){
y1[i]=qu1[i].y;//将排序后的坐标按照y的顺序复制到y1数组中
}
int len=0;
y2[len]=y1[0];//用来储存最优解
for(int i=0;i<j;i++){
if(y1[i]>y2[len])//当y1[i]大于y2[]中最大的数时,将y1[i]放置y2[]首部
y2[++len]=y1[i];
else{
int pos=lower_bound(y2,y2+len+1,y1[i])-y2;//在y2[]中寻找第一个大于或等于y1[i]的位置;
y2[pos]=y1[i]; //lower_bound()函数使用二分的思想查找位置,也可以自己根据二分思想构建函数,这两种方法时间较短,较为合理
} //若不使用二分直接遍历y2[]数组,时间将会超限
}
cout<<len+1<<endl;//输出len+1是因为y2[0]也储存了数;
}
return 0;
}
|