矩形判断
给出平面上4条线段,判断这4条线段是否恰好围成一个面积大于0的矩形。
Input输入第一行是一个整数T(1<=T<=100),代表测试数据的数量。
每组数据包含4行,每行包含4个整数x1, y1, x2, y2 (0 <= x1, y1, x2, y2 <= 100000);其中(x1, y1), (x2,y2)代表一条线段的两个端点。
Output每组数据输出一行YES或者NO,表示输入的4条线段是否恰好围成矩形。
Sample Input
3 0 0 0 1 1 0 1 1 0 1 1 1 1 0 0 0 0 1 2 3 1 0 3 2 3 2 2 3 1 0 0 1 0 1 1 0 1 0 2 0 2 0 1 1 1 1 0 1
Sample Output
YES YES NO
题目解析
本题给出测试数量t,每组测试给出4条线段,要求判断四条线段是否能围成矩形。
本题的数据量t很少,不会超过100,且每条线段有两个端点每组数据4条线段,所以不同的点不会超过8个,所有测试数据中包含的不同的点不会超过800个,这样我们就可以放心大胆的浪费内存空间了。
一、若给出的4条线段可以围成矩形,那么其中必定包含4个不同的端点,利用set的不重复性记录一下4条线段的所有端点,若最后set中的端点不为四个,那这4条线段肯定不能围成一个矩形。
二、若给出的4条线段可以围成矩形,所以围成的图形一定是个封闭图形,4个端点的度一定为2,利用map建立每个端点和其连通端点集的映射,检查每个端点对应连通集合中是否只有两个端点,若不为两个端点,那这4条线段肯定不能围成一个矩形。
三、若给出的4条线段可以围成矩形,则每条线段都会有另一条长度相等的线段与其平行,用vector保存每个线段对应的向量,则若存在两条长度相等且平行的线段,其对应向量相等或符号相反,之后遍历所有向量,与其相等或符号相反的向量定有其本身加上平行相等线段对应的向量共两条,若不为两条那这4条线段肯定不能围成一个矩形。
四、若给出的4条线段可以围成矩形,则每条线段都会有两条与其垂直的线段,因此每条向量都会有两条与其垂直的向量,遍历所有向量获取与其垂直的向量数量,若不为两条那这4条线段肯定不能围成一个矩形。(向量(x1, y1)与(x2, y2)垂直 : x1 * y2 + x2 * y1 == 0)。
若满足以上4条,给出的4条线段可以围成矩形。
AC代码
1 #include <bits/stdc++.h> 2 using namespace std; 3 int t; 4 set<pair<int, int> > nodeSet; //nodeSet储存所有的端点 5 map<pair<int, int>, vector<pair<int, int> > > edgeMap; //edgeMap[i] 储存与i相连的所有点的集合 6 vector<pair<int, int> > vectors; //vectors 储存每条边对应的向量 7 int main() 8 { 9 scanf("%d", &t); //测试数量输入 10 while(t--){ 11 //清空所有容器 12 nodeSet.clear(); 13 edgeMap.clear(); 14 vectors.clear(); 15 //每条输入的信息包括两个点(x1, y1) (x2, y2) 16 int x1, x2, y1, y2; 17 for(int i = 0; i < 4; i++){ //输入四条线段 18 scanf("%d%d%d%d", &x1, &y1, &x2, &y2); 19 pair<int, int> tempNode1, tempNode2, tempVectors; 20 // pair<int, int> tempNode1 记录第一个点 tempNode1.first记录x坐标 tempNode1.second记录y坐标 21 // pair<int, int> tempNode2 记录第二个点 tempNode2.first记录x坐标 tempNode2.second记录y坐标 22 // pair<int, int> tempVectors 记录当前线段对应的向量 tempVectors.first记录x轴位移量 tempVectors.second记录y轴位移量 23 tempNode1.first = x1; 24 tempNode1.second = y1; 25 nodeSet.insert(tempNode1); //nodeSet中加入tempNode1 26 tempNode2.first = x2; 27 tempNode2.second = y2; 28 nodeSet.insert(tempNode2); //nodeSet中加入tempNode2 29 edgeMap[tempNode1].push_back(tempNode2); //tempNode1的连通顶点集中加入tempNode2 30 edgeMap[tempNode2].push_back(tempNode1); //tempNode2的连通顶点集中加入tempNode1 31 tempVectors.first = x2 - x1; //计算x轴位移量 32 tempVectors.second = y2 - y1; //计算y轴位移量 33 vectors.push_back(tempVectors); //向量集vectors中加入tempVectors 34 } 35 if(nodeSet.size() != 4){ //判断端点是否为4个 36 printf("NO "); 37 continue; 38 } 39 bool isRectangle = true; 40 for(auto i : nodeSet){ //判断每个端点的度是否为2 41 if(edgeMap[i].size() != 2){ 42 printf("NO "); 43 isRectangle = false; 44 break; 45 //goto here; 保持气节不要用goto goto是程序的敌人 我一开始用的goto 虽然也AC了不过我改过自新,回头是岸 46 } 47 } 48 if(!isRectangle) 49 continue; 50 isRectangle = true; 51 int cnt; 52 for(auto i : vectors){ //判断每条向量是否有一条向量与其平行且相等 53 cnt = 0; 54 for(auto j : vectors){ 55 if(i == j || (i.first == -j.first && i.second == -j.second)){ 56 cnt++; 57 } 58 } 59 if(cnt != 2){ //加上本身一共两个 60 printf("NO "); 61 isRectangle = false; 62 break; 63 //goto here; 64 } 65 } 66 if(!isRectangle) 67 continue; 68 isRectangle = true; 69 for(auto i : vectors){ //判断每条向量是否有两个与其垂直的向量 70 cnt = 0; 71 for(auto j : vectors){ 72 if(i.first * j.second + j.first * i.second == 0){ 73 cnt++; 74 } 75 } 76 if(cnt != 2){ 77 printf("NO "); 78 isRectangle = false; 79 break; 80 //goto here; 81 } 82 } 83 if(!isRectangle) 84 continue; 85 printf("YES "); 86 //here:; 87 } 88 return 0; 89 }