给出平面上两条线段的两个端点,判断这两条线段是否相交(有一个公共点或有部分重合认为相交)。 如果相交,输出"Yes",否则输出"No"。
输入
第1行:一个数T,表示输入的测试数量(1 <= T <= 1000) 第2 - T + 1行:每行8个数,x1,y1,x2,y2,x3,y3,x4,y4。(-10^8 <= xi, yi <= 10^8) (直线1的两个端点为x1,y1 | x2, y2,直线2的两个端点为x3,y3 | x4, y4)
输出
输出共T行,如果相交输出"Yes",否则输出"No"。
输入样例
2 1 2 2 1 0 0 2 2 -1 1 1 1 0 0 1 -1
输出样例
Yes No
解:
方法一(函数):
已知两点,故可以求得两点所在直线方程Ax+By+C=0。
Ax1+By1=Ax2+By2----->A=k(y2-y1);B=k(x1-x2);C=k(x2y1-x1y2);
另两点位置不应位于直线同侧(四点共线需特殊判断)。
将另两点坐标分别带入方程,比较结果与零的关系,可以判断两点与直线的相对位置关系。
(其实写这道题最大的收获是对于?:运算符的使用有了更多的理解)
1 #include <stdio.h> 2 3 long long num[8]; 4 int cfun() 5 { 6 long long a, b, c, fg1, fg2; 7 a = num[0] - num[2]; 8 b = num[3] - num[1]; 9 c = num[1] * num[2] - num[0] * num[3]; 10 fg1 = a * num[5] + b * num[4] + c > 0 ? 1 : a * num[5] + b * num[4] + c == 0 ? 0 : -1;/// 11 fg2 = a * num[7] + b * num[6] + c > 0 ? 1 : a * num[7] + b * num[6] + c == 0 ? 0 : -1; 12 if (fg1 * fg2 > 0) return 0; 13 else if (0 == (fg1 | fg2))//不加这段if判断也可以ac,但其实程序并没有对于四点一线特殊情况的判断。 14 { 15 int max[2], min[2]; 16 max[0] = num[0] > num[2] ? (min[0] = num[2], num[0]) : (min[0] = num[0], num[2]);/// 17 max[1] = num[4] > num[6] ? (min[1] = num[6], num[4]) : (min[1] = num[4], num[6]); 18 if (max[0] < min[1] || max[1] < min[0]) return 0; 19 else return 1; 20 } 21 a = num[4] - num[6]; 22 b = num[7] - num[5]; 23 c = num[6] * num[5] - num[4] * num[7]; 24 fg1 = a * num[1] + b * num[0] + c > 0 ? 1 : -1; 25 fg2 = a * num[3] + b * num[2] + c > 0 ? 1 : -1; 26 if (fg1 * fg2 > 0) return 0; 27 return 1; 28 } 29 30 int main() 31 { 32 int t; 33 while (scanf_s("%d", &t) != EOF) 34 { 35 //FILE *fp; 36 //fopen_s(&fp, "a.txt", "w" ); 37 while (t--) 38 { 39 scanf_s("%lld%lld%lld%lld%lld%lld%lld%lld", &num[0], &num[1], &num[2], &num[3], &num[4], &num[5], &num[6], &num[7]); 40 fprintf(stdout,"%s\n", cfun() > 0 ? "Yes": "No"); 41 } 42 //fclose(fp); 43 } 44 return 0; 45 }
方法二(向量):
从网上看到的做法,简单的说就是通过两个实验
1.快速排斥实验(判断以两点为对角线的矩形的重合情况)
2.跨立实验(判断两点连线与另两点的相对位置关系【进行两次】)
从而得出答案。
其实两种方法殊途同归,从数学的角度可以借此看出一些一次函数和向量的关系。