【ZOJ - 2967】Colorful Rainbows (栈)

Colorful Rainbows


Time Limit: 2 Seconds      Memory Limit: 65536 KB


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.

Input

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.

Output

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.

Sample Input

2

1
1 1

3
1 0
2 0
3 0

Sample Output

1
2

题意:

给出n条方程式为y=a*x+b的直线,如果存在一点x使得该直线的y大于其他任意一条直线的y,这条直线就是可以被看到的。问有多少条直线可以被看见。(好像两条完全一样的直线,只能看到一条,不知道有没有这种样例)

思路:

将直线用结构体存起来,然后对结构体进行排序(按照a小的在前面,如果a相同,就按照b大的在前面),因为斜率相同时b大的在b小的上面。如果只有两条斜率不同直线,那么都能看到,再加入一条,和之前的两条直线求交点的x坐标,比较然后判断这条直线能不能完全覆盖上一条直线,不能就将上一条直线压回栈内,并跳出,否则就继续循环,因为当前判断的直线在已出现的直线中是一定能看见的,所以在while循环外边压入。

直线判断时两种情况,第一种是3条直线都能看见,但第二种n1这条直线被line[i]覆盖了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
using namespace std;
typedef long long ll;
const double eps=1e-10; 
struct node{
	double a,b;
	friend bool operator<(node a,node b)
	{
		if(fabs(a.a-b.a)<eps)//判断double类型相等要加fabs 
		return a.b>b.b;
		return a.a<b.a; 
	} 
 
}line[8000];
int sgn(double x) {
	if(fabs(x) < eps)return 0;
	if(x < 0) return -1;
	return 1;
}
double getx(node n1,node n2)//已知斜截式求两条直线的交点 
{
	return (n2.b-n1.b)/(n1.a-n2.a);
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		stack<node> sk;
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%lf%lf",&line[i].a,&line[i].b);
		}
		sort(line,line+n);
		sk.push(line[0]);
		double pre=line[0].a;
		for(int i=1;i<n;i++)
		{
			if(sgn(line[i].a-pre)==0)continue; //两条线斜率相等的后面的直接不要,因为是按照b从大到小排序的。好像重合的线段只选一条 
			while(sk.size()!=1)
			{
				node n1=sk.top();
				sk.pop();
				node n2=sk.top();
				double x1=getx(line[i],n2);//这里判断line[i]与n1或n2的都对
				double x2=getx(n1,n2);
				if(sgn(x1-x2)>0)
				{
					sk.push(n1);//新加的线不会覆盖之前的线 
					break;
				}                                          
			}
			sk.push(line[i]);//这条线一定会被压入,之后会不会被弹出不一定
			pre=line[i].a;
		}
		cout<<sk.size()<<endl;
	}
	
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值