第九届河南省程序设计大赛 D 导弹发射

第九届河南省程序设计大赛


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;
}

猜你喜欢

转载自blog.csdn.net/qq_40788630/article/details/80401275