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

半平面交博客
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;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值