1. 程式人生 > >計蒜客 商湯科技的行人檢測(困難)

計蒜客 商湯科技的行人檢測(困難)

觀察列出來的式子,發現對於某一個點實際上是四個未知數兩個方程,有無窮多個解。但是和另外一個點聯立就可以解出來了。這樣的話我們列舉兩個點再驗證,複雜度O(n3)可以通過中等難度。
如果我們隨機兩個點,有0.25的概率正確,這就意味著多試幾次就可以了。比如試20次,正確的概率是0.997
當然求的時候也不要真的解四元方程組。觀察一下還是很容易用計算幾何的方法求出來的。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const
double eps=1e-4; const int maxn=100010; int cmp(double x) { if (x>=eps) return 1; if (fabs(x)<eps) return 0; return -1; } struct Vector { double x,y; void rd() { scanf("%lf%lf",&x,&y); } void wt() { printf("%.10f %.10f\n",x,y); } bool
operator == (const Vector &v) const { return cmp(x-v.x)==0&&cmp(y-v.y)==0; } Vector operator + (const Vector &v) const { return (Vector){x+v.x,y+v.y}; } Vector operator - (const Vector &v) const { return (Vector){x-v.x,y-v.y}; } Vector operator
* (const double &k) const { return (Vector){x*k,y*k}; } }a[maxn],b[maxn]; typedef Vector Point; double dot(Vector v,Vector u) { return v.x*u.x+v.y*u.y; } double cross(Vector v,Vector u) { return v.x*u.y-v.y*u.x; } Vector rot(Vector v,double a) { return (Vector){cos(a)*v.x-sin(a)*v.y,sin(a)*v.x+cos(a)*v.y}; } double angle(Vector v) { return atan2(v.y,v.x); } double len(Vector v) { return sqrt(dot(v,v)); } double dis(Point p,Point q) { return len(p-q); } int n; int check(double Theta,double Scale,Vector D) { int cnt=0; for (int i=1;i<=n;i++) if (!(rot(a[i],Theta)*Scale+D==b[i])) { cnt++; if (cnt*2>n) return 0; } return 1; } int check(int u,int v) { double d1=dis(a[u],a[v]),d2=dis(b[u],b[v]),Scale=d2/d1, Theta=angle(b[v]-b[u])-angle(a[v]-a[u]); Vector D=b[u]-rot(a[u],Theta)*Scale; if (check(Theta,Scale,D)) { printf("%.10f\n%.10f\n",Theta,Scale); D.wt(); return 1; } return 0; } int main() { //freopen("in","r",stdin); int x,y; srand(123); int T=20; scanf("%d",&n); for (int i=1;i<=n;i++) { a[i].rd(); b[i].rd(); } if (n==1) { printf("0\n1\n"); (b[1]-a[1]).wt(); return 0; } while (T--) { x=rand()%n+1; y=rand()%n+1; while (x==y) y=rand()%n+1; if (check(x,y)) return 0; } /*for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) if (check(i,j)) return 0;*/ printf("1\n1\n1 1\n"); }