2019 ICPC Asia Nanjing Regional K.Triangle

题面

题意: 给出三角形的三个顶点和一条线段的一个端点,问是否存在另外一个点和之前的端点构成一条线段,满足落在三角形边上,并且把三角形分成面积相等的两部分,起始点也需要在三角形边上。

题解: 赛后看了一下大家的blog,基本上都是用二分写的,我觉得我的写法还挺好的。首先如果起始点不在三角形边上,直接输出 -1,如果起始点在边上,那么就一定能够找到另外一个点也在三角形边上把这个三角形分为面积相等的两部分,接下来我们就需要去找到这个点,这里我用到了高中时常用的求三角形面积公式 S = 1 2 ∗ sin ⁡ θ ∗ a ∗ b S = \frac{1}{2} * \sin\theta * a * b S=21sinθab
在这里插入图片描述
以上面这张图举例,A B C是给出的三角形的三个顶点, P也是给出的,我们想要找到Q,我的方法是:首先找到P所在的直线,然后找到在这条直线上找到离P远的顶点,以这个点为公共角去寻找Q,我们可以通过下面的方程找到BQ的长度 1 2 ∗ sin ⁡   B ∗ B C ∗ B A = 2 ∗ 1 2 ∗ sin ⁡   B ∗ B P ∗ B Q \frac{1}{2} * \sin\ B * BC * BA = 2 * \frac{1}{2} * \sin\ B * BP * BQ 21sin BBCBA=221sin BBPBQ
可以直接化简到 B C ∗ B A = 2 ∗ B P ∗ B Q BC * BA = 2 * BP * BQ BCBA=2BPBQ
因为只有BQ是未知的所以可以容易得到BQ的值,进而就可以根据BA向量的方向来确定Q的坐标了。

代码

#include<bits/stdc++.h>
using namespace std;
#define eps 1e-8
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);
	}
}P[5], pos[5];

struct Line{
	Point p1, p2;
	Line(){}
	Line(Point p1, Point p2):p1(p1),p2(p2){}
}L[5];

double Dist(Point A, Point B){
	return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}

double Dot(Point A, Point B){
	return A.x * B.x + A.y * B.y;
}

double Cross(Point A, Point B){
	return A.x * B.y - A.y * B.x;
}

bool Point_on_seg(Point p, Line v){
	return sgn(Cross(p - v.p1, v.p2 - v.p1)) == 0 &&
	sgn(Dot(p - v.p1, p - v.p2)) <= 0;
}

int t;
int main () {
	scanf("%d", &t);
	while(t--){
		for(int i = 1; i <= 4; i++) scanf("%lf %lf", &P[i].x, &P[i].y);
		L[1] = Line(P[1], P[2]);
		L[2] = Line(P[2], P[3]);
		L[3] = Line(P[3], P[1]);
		if(Point_on_seg(P[4], L[1]) == 0 && Point_on_seg(P[4], L[2]) == 0 && Point_on_seg(P[4], L[3]) == 0){
			printf("-1\n");
			continue;
		}
		int p = 0;
		for(int i = 1; i <= 3; i++){
			if(Point_on_seg(P[4], L[i]) == 1){
				p = i;
				break;
			}
		}
		if(p == 1)	pos[1] = P[3];	
		else if(p == 2) pos[1] = P[1];
		else pos[1] = P[2];
		if(Dist(P[4], L[p].p1) > Dist(P[4], L[p].p2)){
			pos[2] = L[p].p1;
			pos[3] = L[p].p2;
		} 
		else{
			pos[2] = L[p].p2;	
			pos[3] = L[p].p1;
		} 
		double cnt = Dist(P[4], pos[2]) / Dist(pos[2], pos[3]);
		cnt = 0.5 / cnt;
		double resultX = cnt * (pos[1].x - pos[2].x) + pos[2].x;
		double resultY = cnt * (pos[1].y - pos[2].y) + pos[2].y;
		printf("%.12f %.12f\n", resultX, resultY);
	}
    return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值