Mr. Main and Windmills(计算几何,直线交点)

题目描述

链接

Mr. Main took a train from city s s s to city t t t and passed a plain full of windmills. The train ran in a straight line. A windmill is a machine used for wind power generation. Its fan blades rotate when the wind blows. From his perspective, colorful windmills lined up on the horizon from left to right.

As the train was running, the order of windmills from his perspective was constantly changing: a windmill was originally on the left/right of another, and then changed to its right/left;

Given the coordinates of the windmills, please find the coordinate of him when he just observed the h h h-th windmill exchanged order with other windmills for the k k k-th times. It is guaranteed that any three of the points given, the cities and the windmills, were not collinear, and that all of the windmills were on the same side of the line that the train ran along.

在这里插入图片描述

As shown in the picture, in Mr. Mian’s perspective, B was initially to the left of A, and later to the right of A.

输入描述:

The first line of input contains two integers n n n and m m m, where n n n ( 1 ≤ n ≤ 1000 1\leq n\leq 1000 1n1000) is number of windmills, and m m m ( 1 ≤ m ≤ 1 0 4 1\leq m\leq 10^4 1m104) is number of queries.

The second line contains four integers x s x_s xs , y s y_s ys , x t x_t xt and y t y_t yt ( − 1 0 6 ≤ x s , y s , x t , y t ≤ 1 0 6 -10^6\leq x_s,y_s,x_t,y_t\leq 10^6 106xs,ys,xt,yt106), which are the coordinates of the starting city s s s and destination city t t t.

The next n n n lines describe the windmills, the i i i-th of which contains two integers x i x_i xi, y i y_i yi ( − 1 0 6 ≤ x i , y i ≤ 1 0 6 -10^6\leq x_i,y_i\leq 10^6 106xi,yi106), which are the coordinates of the i i i-th windmill.

The next m m m lines describe the queries, the i i i-th of which contains two integers, h i h_i hi and k i k_i ki ( 1 ≤ h i ≤ n , 1 ≤ k i ≤ 1 0 6 1\leq h_i\leq n,1\leq k_i\leq 10^6 1hin,1ki106), denoting a query for the coordinates when observing the k i k_i ki-th pass of the h i h_i hi-th windmill.

输出描述:

Output m m m lines, each containing two real numbers x i x_i xi, y i y_i yi , representing the coordinates when the h i h_i hi-th windmill is observed to exchange order with other windmills for k k k times; if it does not exist, output − 1 -1 1. Your answer is considered correct if its absolute or relative error with the standard answer is less than 1 0 − 5 10^{-5} 105.

输入

4 2
0 0 5 0
1 3
2 4
4 1
4 5
1 2
3 2

输出

-1
4.6666666667 0.0000000000

思路

大致做法为:求出直线与线段的交点,根据交点距离起点的长度排序,然后输出排序后第 k k k 大的交点的具体位置。

判断直线与线段有没有交点,交点在线段中位置的比例都可以用向量叉乘来做。最后根据交点在线段中的比例也能方便地求出交点的坐标。

值得一提的是,最初我重写 c m p cmp cmp,用 s o r t sort sort 排序,结果段错误。惊讶地发现,正是 s o r t sort sort 递归太多而造成堆栈溢出。改用比较稳的归并排序后,就过了。

之后分析了一下,因为我重写 c m p cmp cmp 的时候,定义的是:如果直线与线段没有交点,那么它的优先级是最大的,会排到序列的末尾。这听起来没什么问题,但是,快速排序选择基准元素的时候,如果选到了没有交点的元素,那么,一趟排序下来,只能排一个元素,这种情况下递归深度就没有保证了。

#include<bits/stdc++.h>
using namespace std;
const int N=10100;
int T,n,m,ord[N],h,k,b[N];
double sx,sy,ex,ey,x[N],y[N];

bool cmp(int a,int b){
	double up=(x[b]-x[h])*(sy-y[h])-(sx-x[h])*(y[b]-y[h]);
	double down=(x[b]-x[h])*(ey-y[h])-(ex-x[h])*(y[b]-y[h]);
	if(up*down>=0) return true;
	double u=up/down;
	up=(x[a]-x[h])*(sy-y[h])-(sx-x[h])*(y[a]-y[h]);
	down=(x[a]-x[h])*(ey-y[h])-(ex-x[h])*(y[a]-y[h]);
	if(up*down>=0) return false;
	double v=up/down;
	return u<v;
}

void merge(int l,int r){
	if(r<=l) return;
	int mid=(l+r)>>1,i=l,j=mid+1;
	merge(l,mid); merge(mid+1,r);
	for(int k=l;k<=r;k++)
		if((i<=mid&&cmp(ord[i],ord[j]))||j>r) b[k]=ord[i++];
		else b[k]=ord[j++];
	for(int k=l;k<=r;k++) ord[k]=b[k];
}

void solve(){
	cin>>h>>k;
	if(k>=n) return (void)(cout<<"-1\n");
	//sort(ord+1,ord+n+1,cmp);	//用快排会堆栈溢出
	merge(1,n);
	double up=(x[ord[k]]-x[h])*(sy-y[h])-(sx-x[h])*(y[ord[k]]-y[h]);
	double down=(x[ord[k]]-x[h])*(ey-y[h])-(ex-x[h])*(y[ord[k]]-y[h]);
	if(up*down>=0) return (void)(cout<<"-1\n");
	double p=abs(up)/(abs(down)+abs(up));
	double nx=(ex-sx)*p+sx;
	double ny=(ey-sy)*p+sy;
	cout<<fixed<<setprecision(10)<<nx<<" "<<ny<<"\n";
}

int main(){
	ios::sync_with_stdio(false);
	cin>>n>>m;
	cin>>sx>>sy>>ex>>ey;
	for(int i=1;i<=n;i++) cin>>x[i]>>y[i],ord[i]=i;
	while(m--) solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_51864047

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值