C - Colorful Rainbows----(2015 summer training #4 (Qualifying))

C - Colorful Rainbows
时限:2000MS     内存:65536KB     64位IO格式:%lld & %llu

问题描述

Evelyn likes drawing very much. Today, she draws lots of rainbows on white paper of infinite size, each using a different color. Since there're too many rainbows now, she wonders, how many of them can be seen?

For simplicity, each rainbow Li is represented as a non-vertical line specified by the equation: y=aix+bi. A rainbow Li can be seen if there exists some x-coordinate x0 at which, its y-coordinate is strictly greater than y-coordinates of any other rainbows: aix0+bi >ajx0+bj for all j != i.

Now, your task is, given the set of rainbows drawn, figure out the number of rainbows that can be seen.


输入

Standard input will contain multiple test cases. The first line of the input is a single integer T (1 <= T <= 60) which is the number of test cases. And it will be followed by T consecutive test cases.

There's a blank line before every case. In each test case, there will first be an integer n (1 <= n <= 5000), which is the number of rainbows. Then n consecutive real number pairs follow. Each pair contains two real numbers, ai and bi, representing rainbow Li: y=aix+bi. No two rainbows will be the same, that is to say, have the same a and b.


输出

Results should be directed to standard output. The output of each test case should be a single integer, which is the number of rainbows that can be seen.


样例输入

2

1
1 1

3
1 0
2 0
3 0

样例输出

1
2

分析:

以下为摘抄的讲解:
    给定直线,对每条直线,传说解不等式组可以过,直接看是否存在一个点在直线之上。(左端点取max,右端点取min,如果左>=右,直接break掉)。有点ft...O(n^2) n=5000 rp好的可以过.... 
    我用的方法类似于凸包,先把所有直线按照斜率a由小到大排序,斜率相同取b较大的,扔掉b小的。于是所有直线斜率不同。准备一个栈,栈里面存放上一次能看到的“最上面”的直线以及这条直线能看到的范围x(x值右边的部分可以被看到)。初始时,把斜率最小的直线入栈,并记录x值为-inf。然后对第i条直线,所做的是用第i条直线和栈顶直线求交点x,如果这个x值不大于栈顶的x值,则把栈顶元素弹出,继续求交,否则退出。这种判断操作直到栈为空,或者当前栈顶的x值大于栈顶的x值。然后把第i条直线入栈,继续,看后面的直线。最后栈中的直线数就是能看到的。这种做法类似于凸包的方法,除去排序外,每条直线至多出入栈一次,复杂度O(n)。总复杂度是O(nlogn)。
看了别人的讲解,自己写的代码。


CODE:

#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;

const double INF=1e9;
int t,n;

struct node{
    double a,b;
}p[5005];

int cmp(node x,node y){
    return x.a<y.a;
}

int main()
{
    cin>>t;
    while(t--){
        cin>>n;
        double x,y;
        int cnt=0;
        for(int i=0;i<n;i++){
            cin>>x>>y;
            bool flag=false;
            for(int j=0;j<cnt;j++){
                if(p[j].a==x&&p[j].b<y){
                    p[j].b=y;
                    flag=true;
                    break;
                }
            }
            if(!flag){
                p[cnt].a=x;
                p[cnt++].b=y;
            }
        }
        sort(p,p+cnt,cmp);
        stack<double> s1;
        stack<double> s2;
        stack<double> s3;
        s3.push(-INF);
        s1.push(p[0].a),s2.push(p[0].b);
        int ans=1;
        for(int i=1;i<cnt;i++){
            double nowa=s1.top();
            double nowb=s2.top();
            double tx=(p[i].b-nowb)/(nowa-p[i].a);
            double nowx=s3.top();
            if(tx>nowx){
                s3.push(tx);
                s1.push(p[i].a);
                s2.push(p[i].b);
                ans++;
            }
            else{
                while(!s1.empty()){
                    s1.pop(),s2.pop(),s3.pop();
                    if(s1.empty()){
                        s3.push(-INF);
                        s1.push(p[i].a);
                        s2.push(p[i].b);
                        break;
                    }
                    double nowa=s1.top();
                    double nowb=s2.top();
                    double tx=(p[i].b-nowb)/(nowa-p[i].a);
                    double nowx=s3.top();
                    if(tx>nowx){
                        s3.push(tx);
                        s1.push(p[i].a);
                        s2.push(p[i].b);
                        break;
                    }
                    else
                        ans--;
                }
            }
        }
        cout<<ans<<endl;
        while(!s1.empty()) s1.pop();
        while(!s2.empty()) s2.pop();
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值