计蒜客 商汤科技的行人检测(困难)

观察列出来的式子,发现对于某一个点实际上是四个未知数两个方程,有无穷多个解。但是和另外一个点联立就可以解出来了。这样的话我们枚举两个点再验证,复杂度 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");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值