整理房间
整理房间
http://www.nowcoder.com/questionTerminal/c32f4c74446541a1ad2abbe54476681f
题目难度:三星
考察点:计算几何
方法:计算几何、枚举
- 分析:
对于这道题来说我们有如下需要考虑的地方:
(1). 一个点A(x1,y1)围绕一个点B(x2,y2)逆时针旋转90°一次,对应坐标A的变化?旋转多次呢?
我们都知道如果B是原点的话,那么逆时针旋转90°一次之后坐标A(x1,y1)将变为C(y1, x1),那么如果B不是原点呢?我们将整个坐标系进行移动,将B移动到原点,那么A的坐标就会变为(x1-x2,y1-y2),那么此时进行逆时针旋转90°,A的坐标就会变为C(y1-y2,x1-x2)。注意,此时C的坐标是相对于B点来说的,如果相对于原点来说的话,就变成D(y1-y2+x2,x1-x2+y2),那么总结一下:就是点A(x1,y1)围绕一个点B(x2,y2)逆时针旋转90°一次之后的坐标变为D(y1-y2+x2,x1-x2+y2)。如果旋转多次的话,就把A点变为D,继续循环下去(最多旋转3次,因为旋转4次就相当于没有旋转)
(2). 如何判断4个点是否能够构成正方形?
我们只要获取4条边的边长,如果4条边相等且不为0,同时满足有一个角是直角,那么这4个点就能够构成正方形。首先我们将这4个点按照x坐标排序,如果x坐标相同按照纵坐标排序(都是从小到大排序)。那么排完序之后的坐标记作p0,p1,p2,p3,那么4条边的边长分别为p0p1, p0p2 p1p3, p2p3,判断一个角是否为直角,可以判断它们的点乘是否为0,如果为0证明是直角,否则不是直角.
(3). 如何计算移动最少次数使得四个点构成正方形呢?
我们可以进行枚举,一共有4个点,每个点可以旋转4次,一共是4^4种方法,我们将这些方法全部枚举出来,获得最小值就好了。
算法实现:
(1).首先进行枚举,4个变量i,j,k,l分别表示4个点的旋转次数,那么移动次数就等于i+j+k+l
(2).对于旋转之后的4个点,我们判断是否能够组成正方形即可,判断是否为正方形的方法已经在上面叙述了。
(3). 输出最小移动次数。
复杂度分析:
时间复杂度:O(4^4*n)
空间复杂度:O(1)代码:
#include <bits/stdc++.h> using namespace std; struct Point { int x, y; }; bool cmp(Point A, Point B) { if(A.x == B.x) return A.y < B.y; return A.x < B.x; } int Dis2(Point A, Point B) { return (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y); } //AB⊥BC bool isRightAngle(Point A, Point B, Point C) { int x = (B.x-A.x)*(C.x-B.x); int y = (B.y-A.y)*(C.y-B.y); return x+y==0; } bool isSqure(Point p[4]) { sort(p, p+4, cmp); int dis[4]; dis[0] = Dis2(p[0], p[1]); dis[1] = Dis2(p[0], p[2]); dis[2] = Dis2(p[1], p[3]); dis[3] = Dis2(p[2], p[3]); sort(dis, dis+4); if(dis[0]==dis[3] && dis[0] && isRightAngle(p[1], p[0], p[2])) return true; return false; } Point rotate(Point A, Point B, int t) { Point tmp; for(int i=0; i<t; i++) { tmp.x = B.x - A.y + B.y; tmp.y = A.x - B.x + B.y; A = tmp; } return A; } Point a[4], b[4], p[4]; int main() { int n; cin>>n; while(n--) { for(int i=0; i<4; i++) cin>>a[i].x>>a[i].y>>b[i].x>>b[i].y; int ans = 20; for(int i=0; i<4; i++) { for(int j=0; j<4; j++) { for(int k=0; k<4; k++) { for(int l=0; l<4; l++) { p[0] = rotate(a[0], b[0], i); p[1] = rotate(a[1], b[1], j); p[2] = rotate(a[2], b[2], k); p[3] = rotate(a[3], b[3], l); if(isSqure(p)) ans = min(ans, i+j+k+l); } } } } if(ans == 20) ans = -1; cout<<ans<<endl; } return 0; }
```