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
- T ≤ 20
- 0 < N ≤ 50000
- 0 < p, v ≤ 2000,000,000
- An athlete’s position is the distant between him/her and the start line.
- 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
半平面交博客
https://blog.csdn.net/gpc_123/article/details/122741381
题意 : n个人(0 < n <= 5e4)在一条笔直的路上跑马拉松.设初始时每个人处于不同的位置,然后每个人都以自己恒定的速度不停的往前跑;
给定这n个人的初始位置和速度,问有多少人可能在某一时刻成为第一 ?
**思路 😗*半平面交的裸题
以时间为横轴,距离为纵轴;每个人的初始位置和速度构成的有向直线就是他们的运动轨迹;我们加两条直线构成封闭的凸面多边形;最终构成的凸多边形的顶点数就是结果
AC代码 :
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double INF = 1e12;
const double pi = acos(-1.0);//高精度圆周率
const double eps = 1e-8;//偏差值
const int maxn = 104;//点的数量
//判断是否等于零,返回0为等于零,返回-1为小于,1为大于
int sgn(double x) {
if (fabs(x) < eps)return 0;
else return x < 0 ? -1 : 1;
}
struct Point {
double x, y;
Point() {}
Point(double x, double y) : x(x), y(y) {}
Point operator+(Point B) { return Point(x + B.x, y + B.y); }
Point operator-(Point B) { return Point(x - B.x, y - B.y); }
Point operator*(double k) { return Point(x * k, y * k); }//放大k倍
};
typedef Point Vector;
double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x;}
struct Line{
Point p; //直线上一个点
Vector v; //方向向量,左边是半平面
double ang; //极角,从x正半轴旋转到v的角度
Line(){};
Line(Point p,Vector v):p(p),v(v){ang = atan2(v.y,v.x);}
friend bool operator < (Line a,Line b){return a.ang < b.ang;}//用于排序
};
//p在线L的左边
bool OnLeft(Line L,Point p){return sgn(Cross(L.v,p - L.p )) > 0;}
Point Cross_point(Line a,Line b){ //两直线的交点
Vector u = a.p - b.p;
double t = Cross(b.v, u) / Cross(a.v, b.v);
return a.p + a.v * t;
}
vector<Point> HPI(vector<Line> L){
int n=L.size();
sort(L.begin(),L.end());//将所有半平面按照极角排序。
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]=Cross_point(q[last-1],q[last]);//计算队列顶部半平面交点。
}
while(first<last&&!OnLeft(q[first],p[last-1]))last--;//删除队列顶部的无用半平面。
if(last-first<=1)return ans;//半平面退化
p[last]=Cross_point(q[last],q[first]);//计算队列顶部与首部的交点。
for(int i=first;i<=last;i++)ans.push_back(p[i]);//将队列中的点复制。
return ans;
}
int main(){
int T,n;
cin>>T;
while(T--){
cin>>n;
vector<Line> L;
L.push_back(Line(Point(0,INF),Point(-1,0))); // y极大的向左的直线,平行于x轴
L.push_back(Line(Point(0,0),Point(0,-1))); // 反向y轴
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;
}