题意:给定 4n * 2 个坐标,分成 n组,让你判断,点绕点的最少次数使得四个点是一个正方形的顶点。
析:那么就一个一个的判断,n 很小,不会超时,四个点分别从不转然后转一次,转两次。。。转四次,就这样算下去,那么如何判断是不是正方形呢?这样判定就行,把每个边都求出来,然后判定,
这里肯定有四个边是一样,另外两个是一样的,而且还不是0,因为可能重合,关键是旋转后怎么算呢?有两个公式,假设点(x, y)绕点(a, b)转 x 角度,那么旋转后的坐标为 (xx, yy),应该是,
xx = (x - a) cos x - (y-b) sin x + a; yy = (x-a) sin x + (y-b) cos x + b;这就是转任意角度的结果。那么剩下的就很简单了,注意,如果用int 可能会溢出,用double注意精度。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int mod = 1e9 + 7; const int maxn = 400 + 5; int a[maxn], b[maxn], x[maxn], y[maxn]; int xx[5], yy[5]; void rot(int t, int *s){//旋转 for(int i = 0; i < 4; ++i){//四个点旋转 xx[t+i] = x[t+i], yy[t+i] = y[t+i]; for(int j = 0; j < s[i]; ++j){//第 i 个数旋转 int xxx = xx[t+i]; xx[t+i] = a[t+i] - yy[t+i] + b[t+i]; yy[t+i] = xxx - a[t+i] + b[t+i]; } } } bool judge(int t, int *x, int *y){ vector<LL> v; for(int i = 0; i < 4; ++i) for(int j = 0 ; j < 4; ++j){ if(i == j) continue; LL xx = ((LL)x[t+i]-(LL)x[t+j]) * ((LL)x[t+i]-(LL)x[t+j]) + ((LL)y[t+i]-(LL)y[t+j]) * ((LL)y[t+i]-(LL)y[t+j]);//计算边长 v.push_back(xx);//记录边长 } sort(v.begin(), v.end());//排序 int tt = 0, ii = 0;//计算数量 for(int i = 0 ; i < 12; ++i){ if(v[i] == v[0] && v[i]) ++tt; else if(v[i] == v[11] && v[i]) ++ii; } if(tt == 8 && ii == 4) return true; return false; } int solve(int t){ int ans = 1000; 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){ if(ans < i + j + k +l) continue;//如果小于才循环 int s[] = {i, j, k, l}; rot(t, s); if(judge(t, xx, yy)) ans = i + j + k + l; } return ans == 1000 ? -1 : ans; } int main(){ int n; cin >> n; for(int i = 1; i <= 4*n; ++i) scanf("%d %d %d %d", &x[i], &y[i], &a[i], &b[i]); for(int i = 1; i < 4*n; i += 4) cout << solve(i) << endl; return 0; }