首页 > 代码库 > HDU 2297 半平面交

HDU 2297 半平面交

Run

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 640    Accepted Submission(s): 181


Problem Description
Since members of Wuhan University ACM Team are lack of exercise, they plan to participate in a ten-thousand-people Marathon. It is common that the athletes run very fast at first but slow down later on. Start from this moment, we can assume that everyone is moving forward in a constant speed. ACMers love algorithms, so they want to know not only the result but also who may be in the leading position. Now we know all athletes‘ position and speed at a specific moment. The problem is, starting from this moment, how many athletes may be the leader. Please notice that there‘s no leader if two or more athletes are at the leading position at the same time. No two athletes may have the same speed.
 

Input
The input consists of several test cases. The first line of input consists of an integer T, indicating the number of test cases. The first line of each test case consists of an integer N, indicating the number of athletes. Each of the following N lines consists of two integers: p, v, indicating an athlete‘s position and speed.

Technical Specification

1. T ≤ 20
2. 0 < N ≤ 50000
3. 0 < p, v ≤ 2000,000,000
4. An athlete‘s position is the distant between him/her and the start line.
5. The Marathon is so long that you can assume there‘s no finishline.
 

Output
For each test case, output the number of possible leaders on a separate line.
 

Sample Input
1 3 1 1 2 3 3 2
 

Sample Output
2


给定n个人的比赛状况,现在已经跑得距离,以及比赛速度,时间无限,问有多少人可以在某一段时间跑到第一名。

以时间为横轴,距离为纵轴,每一个人的跑步状况可以等效于已知起点,速度的一条射线我们可以加一个边界,对这些半平面求交,很明显可以选中的半平面代表的选手才可以跑到第一名。减去认为加的边界2,就可以得到答案。

代码:

/* ***********************************************
Author :_rabbit
Created Time :2014/5/4 15:03:55
File Name :20.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 10000000000400.0
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
int dcmp(double x){
	if(fabs(x)<eps)return 0;
	return x>0?1:-1;
}
struct Point{
	double x,y;
	Point(double _x=0,double _y=0){
		x=_x;y=_y;
	}
};
Point operator + (const Point &a,const Point &b){
	return Point(a.x+b.x,a.y+b.y);
}
Point operator - (const Point &a,const Point &b){
	return Point(a.x-b.x,a.y-b.y);
}
Point operator * (const Point &a,const double &p){
	return Point(a.x*p,a.y*p);
}
Point operator / (const Point &a,const double &p){
	return Point(a.x/p,a.y/p);
}
bool operator < (const Point &a,const Point &b){
	return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
bool operator == (const Point &a,const Point &b){
	return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double Dot(Point  a,Point b){
	return a.x*b.x+a.y*b.y;
}
double Length(Point a){
	return sqrt(Dot(a,a));
}
double Angle(Point a,Point b){
	return acos(Dot(a,b)/Length(a)/Length(b));
}
double angle(Point a){
	return atan2(a.y,a.x);
}
double Cross(Point a,Point b){
	return a.x*b.y-a.y*b.x;
}
Point vecunit(Point a){
	return a/Length(a);
}
Point Normal(Point a){
	return Point(-a.y,a.x)/Length(a);
}
Point Rotate(Point a,double rad){
	return Point(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));
}
double Area2(Point a,Point b,Point c){
	return Length(Cross(b-a,c-a));
}
struct Line{
	Point p,v;
	double ang;
	Line(){};
	Line(Point p,Point v):p(p),v(v){
		ang=atan2(v.y,v.x);
	}
	bool operator < (const Line &L) const {
		return ang<L.ang;
	}
};
bool OnLeft(const Line &L,const Point &p){
	return dcmp(Cross(L.v,p-L.p))>0;
}
Point GetLineIntersection(Point p,Point v,Point q,Point w){
	Point u=p-q;
	double t=Cross(w,u)/Cross(v,w);
	return p+v*t;
}
Point GetLineIntersection(Line a,Line b){
	return GetLineIntersection(a.p,a.v,b.p,b.v);
}
vector<Point> HPI(vector<Line> L){
	int n=L.size();
	sort(L.begin(),L.end());//将所有半平面按照极角排序。
	/*for(int i=0;i<n;i++){
		cout<<"han  "<<i<<" ";
		printf("%.2lf  %.2lf  %.2lf  %.2lf  %.2lf\n",L[i].p.x,L[i].p.y,L[i].v.x,L[i].v.y,L[i].ang);
	}*/
	int first,last;
	vector<Point> p(n);
	vector<Line> q(n);
	vector<Point> ans;
	q[first=last=0]=L[0];
	for(int i=1;i<n;i++){
		while(first<last&&!OnLeft(L[i],p[last-1]))last--;//删除顶部的半平面
		while(first<last&&!OnLeft(L[i],p[first]))first++;//删除底部的半平面
		q[++last]=L[i];//将当前的半平面假如双端队列顶部。
		if(fabs(Cross(q[last].v,q[last-1].v))<eps){//对于极角相同的,选择性保留一个。
			last--;
			if(OnLeft(q[last],L[i].p))q[last]=L[i];
		}
		if(first<last)p[last-1]=GetLineIntersection(q[last-1],q[last]);//计算队列顶部半平面交点。
	}
	while(first<last&&!OnLeft(q[first],p[last-1]))last--;//删除队列顶部的无用半平面。
	if(last-first<=1)return ans;//半平面退化
	p[last]=GetLineIntersection(q[last],q[first]);//计算队列顶部与首部的交点。
	for(int i=first;i<=last;i++)ans.push_back(p[i]);//将队列中的点复制。
	return ans;
}
double PolyArea(vector<Point> p){
	int n=p.size();
	double ans=0;
	for(int i=1;i<n-1;i++)
		ans+=Cross(p[i]-p[0],p[i+1]-p[0]);
	return fabs(ans)/2;
}
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int T,n;
	 cin>>T;
	 while(T--){
		 cin>>n;
		 vector<Line> L;
		 L.push_back(Line(Point(INF,INF),Point(-1,0)));
		 L.push_back(Line(Point(0,INF),Point(0,-1)));
		 while(n--){
			 double a,b;
			 scanf("%lf%lf",&a,&b);
			 L.push_back(Line(Point(0,a),Point(1,b)));
		 }
		 vector<Point> ans=HPI(L);
		// for(int i=0;i<ans.size();i++)cout<<ans[i].x<<" "<<ans[i].y<<endl;
		 printf("%d\n",ans.size()-2);
	 }
     return 0;
}