13B - Letter A

原题链接

这是一道基础的计算几何题

题意:
给你任意的三条线段的坐标,问能否组成合格的A。
这里有三条限制:
1.任意其中两条必有一个公共点,注意,一定是一个,并且没有公共点的第三条边的两个端点要在那两条有公共边的边上;
2.两条有公共点的边的夹角大于0度小于等于90度;
3.这两条边被第三条边所划分的,分别各自被划分为两条,其中较长的不能大于较短的4倍。

思路:直接按照要求进行判断,注意第三条线段的点不落在组成A的左右两条边的线段上的情况(但是落在对应的直线上)

代码如下

struct segment{
	ll x1, y1, x2, y2;
}seg[3]; 

struct point{
	ll x, y;
};

bool judge(ll x1, ll y1, ll x2, ll y2, ll x3, ll y3)	//判断三点是否共线 
{
	return (x2 - x1) * (y3 - y2) == (y2 - y1) * (x3 - x2);
}

double dist(ll x1, ll y1, ll x2, ll y2)		//计算两点距离 
{
	double x = x1 - x2, y = y1 - y2;
	return sqrt(x * x + y * y);
}

bool inl(ll x1, ll y1, ll x2, ll y2, ll x3, ll y3)	//判断 C(x3, y3)是否在线段内 
{
	ll xa = x3 - x1, xb = x3 - x2;
	ll ya = y3 - y1, yb = y3 - y2;
	if(xa * xb > 0 || ya * yb > 0) return false;
	return true;
}

int main()
{
	IOS; 
	ll T;
	cin >> T;
	while(T --)
	{
		for(ll i = 0 ; i < 3 ; i ++)
			cin >> seg[i].x1 >> seg[i].y1 >> seg[i].x2 >> seg[i].y2;
		ll a = -1, b = -1, c = -1;
		
		//找到有公共点的两个线段 
		for(ll i = 0 ; i < 3 ; i ++)
			for(ll j = i + 1 ; j < 3 ; j ++)
			{
				if(seg[i].x1 == seg[j].x1 && seg[i].y1 == seg[j].y1)
					a = i, b = j;
				else if(seg[i].x1 == seg[j].x2 && seg[i].y1 == seg[j].y2)
					a = i, b = j;
				else if(seg[i].x2 == seg[j].x1 && seg[i].y2 == seg[j].y1)
					a = i, b = j;
				else if(seg[i].x2 == seg[j].x2 && seg[i].y2 == seg[j].y2)
					a = i, b = j;
			}
		
		
		if(a == -1 || b == -1)
		{
			cout << "NO\n";
			continue;
		}
		
		//应用余弦定理计算角度
		double angle, s, maxd, mind;
		double d1 = dist(seg[a].x1, seg[a].y1, seg[a].x2, seg[a].y2);
		double d2 = dist(seg[b].x1, seg[b].y1, seg[b].x2, seg[b].y2);
		
		if(seg[a].x1 == seg[b].x1 && seg[a].y1 == seg[b].y1) 
			s = (seg[a].x2 - seg[a].x1) * (seg[b].x2 - seg[b].x1) + (seg[a].y2 - seg[a].y1) * (seg[b].y2 - seg[b].y1);
		else if(seg[a].x1 == seg[b].x2 && seg[a].y1 == seg[b].y2) 
			s = (seg[a].x2 - seg[a].x1) * (seg[b].x1 - seg[b].x2) + (seg[a].y2 - seg[a].y1) * (seg[b].y1 - seg[b].y2);
		else if(seg[a].x2 == seg[b].x1 && seg[a].y2 == seg[b].y1)
			s = (seg[a].x1 - seg[a].x2) * (seg[b].x2 - seg[b].x1) + (seg[a].y1 - seg[a].y2) * (seg[b].y2 - seg[b].y1);
		else s = (seg[a].x1 - seg[a].x2) * (seg[b].x1 - seg[b].x2) + (seg[a].y1 - seg[a].y2) * (seg[b].y1 - seg[b].y2);
		//计算出夹角 
		angle = acos(s / (d1 * d2));
		if(angle > pi / 2.0 || angle <= 0)
		{
			cout << "NO\n";
			continue;			
		}
		// 确定第三条边 
		for(ll i = 0 ; i < 3 ; i ++)
			if(i != a && i != b) 
				c = i;
		
		//确定第三条线段在 a 和 b上的点 pa 和 pb 
		point pa = {mod, mod}, pb = {mod, mod};
		if(judge(seg[a].x1, seg[a].y1, seg[a].x2, seg[a].y2, seg[c].x1, seg[c].y1))
			pa = {seg[c].x1, seg[c].y1};
		else if(judge(seg[a].x1, seg[a].y1, seg[a].x2, seg[a].y2, seg[c].x2, seg[c].y2))
			pa = {seg[c].x2, seg[c].y2};
			
		if(judge(seg[b].x1, seg[b].y1, seg[b].x2, seg[b].y2, seg[c].x1, seg[c].y1))
			pb = {seg[c].x1, seg[c].y1};
		else if(judge(seg[b].x1, seg[b].y1, seg[b].x2, seg[b].y2, seg[c].x2, seg[c].y2))
			pb = {seg[c].x2, seg[c].y2};
		
		bool flag = true;
		if(pa.x == pb.x && pa.y == pb.y) flag = false;
		if(pa.x == mod || pa.y == mod || pb.x == mod || pb.y == mod) flag = false;
		// 计算分割的两部分是否不满足配比 
		d1 = dist(pa.x, pa.y, seg[a].x1, seg[a].y1);
		d2 = dist(pa.x, pa.y, seg[a].x2, seg[a].y2);
		maxd = max(d1, d2);
		mind = min(d1, d2);
		if(mind * 4 < maxd) flag = false;
		
		d1 = dist(pb.x, pb.y, seg[b].x1, seg[b].y1);
		d2 = dist(pb.x, pb.y, seg[b].x2, seg[b].y2);
		maxd = max(d1, d2);
		mind = min(d1, d2);	
		if(mind * 4 < maxd) flag = false;	
		
		//如果点不在线段内 
		if(!inl(seg[a].x1, seg[a].y1, seg[a].x2, seg[a].y2, pa.x, pa.y))	flag = false;
		if(!inl(seg[b].x1, seg[b].y1, seg[b].x2, seg[b].y2, pb.x, pb.y))	flag = false;
		 
		if(!flag) cout << "NO\n";
		else cout << "YES\n";
	}
	
	return 0;
}
posted @ 2021-04-16 16:41  beatlesss  阅读(55)  评论(0编辑  收藏  举报