问题描述
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;
}