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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章