• 计蒜客 商汤科技的行人检测(随机化+计算几何)


    题目链接

    简单

    中等

    困难

    简单版本

    直接统计答案,数目到达一半即可。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    int n;
    int a, b, c, d;
    pair <int, int> ans;
    map <pair <int, int >, int > mp;
    
    int main(){
    
    	scanf("%d", &n);
    	rep(i, 1, n){
    		scanf("%d%d%d%d", &a, &b, &c, &d);
    		++mp[{c - a, d - b}];
    		if (mp[{c - a, d - b}] >= (n + 1) / 2) ans = {c - a, d - b};
    	}
    
    	printf("%d %d
    ", ans.first, ans.second);
    	return 0;
    
    
    
    }
    

    中等版本

    题面和简单版本不一样。

    我们可以通过两组变化解出一组行人的移动参数

    具体的解法是

    scale可以通过变换后两点之间距离的倍数关系求出

    旋转坐标前两个点形成的直线向量A,和旋转坐标后的两个点形成的直线向量B

    那么θ就是A,B的夹角,然后用一下公式$cosθ=frac{A*B}{|A|*|B|}$, 就能算出角度了。

    那么dx, dy就很好求了。

    我们两两枚举所有的变化,求出参数,然后验证一下在n组变化中吻合次数是否到达一半。

    (注意eps要开1e-4,我之前开了1e-8一直WA)

    时间复杂度$O(n^3)$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    const int N = 1e5 + 10;
    const double eps = 1e-4;
    
    struct node{
    	double x, y;
    	void scan() { scanf("%lf%lf", &x, &y); }
    	void print(){ printf("%.12f %.12f
    ", x, y); }
    
    	friend node operator - (const node &a, const node &b){
    		return node{a.x - b.x, a.y - b.y};
    	}
    
    	friend node operator + (const node &a, const node &b){
    		return node{a.x + b.x, a.y + b.y};
    	}
    
    	friend bool operator == (const node &a, const node &b){
    		return fabs(a.x - b.x) < eps && fabs(a.y - b.y) < eps;
    	}
    
    } a[N], b[N];
    
    struct Node{
    	double cita, scale, dx, dy;
    	void print(){ printf("%.12f
    %.12f
    %.12f %.12f
    ", cita, scale, dx, dy); }
    } ret;
    
    int n;
    
    double dis(const node &a, const node &b){
    	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    double angle(const node &a){
    	return atan2(a.y, a.x);
    }
    
    node calc(double ang, node a){
    	double x = a.x, y = a.y;
    	a.x = x * cos(ang) - y * sin(ang);
    	a.y = x * sin(ang) + y * cos(ang);
    	return a;
    }
    
    bool judge(Node cnt){
    	int ret = 0;
    	node now;
    	rep(i, 1, n){
    		now = calc(cnt.cita, a[i]);
    		now.x *= cnt.scale;
    		now.y *= cnt.scale;
    		now.x += cnt.dx;
    		now.y += cnt.dy;
    		if (now == b[i]) continue;
    		++ret;
    		if (ret * 2 > n) return false;
    	}
    
    	return true;
    }
    
    Node solve(int x, int y){
    	Node ret  = {0, 0, 0, 0};
    	ret.cita  = angle(b[y] - b[x]) - angle(a[y] - a[x]);
    	ret.scale = dis(b[x], b[y]) / dis(a[x], a[y]);
    	node cnt  = calc(ret.cita, a[x]);
    	ret.dx    = b[x].x - ret.scale * cnt.x;
    	ret.dy    = b[x].y - ret.scale * cnt.y;
    	return ret;
    }
    
    int main(){
    
    	scanf("%d", &n);
    	rep(i, 1, n){
    		a[i].scan();
    		b[i].scan();
    	}
    
    	if (n == 1){
    		puts("0.000000000000");
    		puts("1.000000000000");
    		node c = b[1] - a[1];
    		c.print();
    		return 0;
    	}
    
    	bool flag = false;
    
    	rep(i, 1, n - 1){
    		rep(j, i + 1, n){
    			ret = solve(i, j);
    			if (judge(ret)){
    				flag = true;
    				break;
    			}
    		}
    		if (flag) break;
    	}
    
    	ret.print();
    	return 0;
    }
    

    困难版本

    因为错误的参数不超过一半,那么我们选择一个点,他的参数错误的概率不超过0.5

    所以我们选择两个点,这两个点至少有一个点的参数错误的概率不超过0.75

    我们随机枚举100次,那么枚举得到的的100组参数都错的概率为$0.75^{100}$,几乎为0

    但是中等的代码交到困难版本这边是TLE的,为什么呢。

    因为中等的代码是有序枚举的,如果前面很多的点参数都是错的,那么就枚举不到正确答案,于是就TLE了。

    时间复杂度$O(100n)$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    const int N = 1e5 + 10;
    const double eps = 1e-4;
    
    struct node{
    	double x, y;
    	void scan() { scanf("%lf%lf", &x, &y); }
    	void print(){ printf("%.12f %.12f
    ", x, y); }
    
    	friend node operator - (const node &a, const node &b){
    		return node{a.x - b.x, a.y - b.y};
    	}
    
    	friend node operator + (const node &a, const node &b){
    		return node{a.x + b.x, a.y + b.y};
    	}
    
    	friend bool operator == (const node &a, const node &b){
    		return fabs(a.x - b.x) < eps && fabs(a.y - b.y) < eps;
    	}
    
    } a[N], b[N];
    
    struct Node{
    	double cita, scale, dx, dy;
    	void print(){ printf("%.12f
    %.12f
    %.12f %.12f
    ", cita, scale, dx, dy); }
    } ret;
    
    int n;
    
    double dis(const node &a, const node &b){
    	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    double angle(const node &a){
    	return atan2(a.y, a.x);
    }
    
    node calc(double ang, node a){
    	double x = a.x, y = a.y;
    	a.x = x * cos(ang) - y * sin(ang);
    	a.y = x * sin(ang) + y * cos(ang);
    	return a;
    }
    
    bool judge(Node cnt){
    	int ret = 0;
    	node now;
    	rep(i, 1, n){
    		now = calc(cnt.cita, a[i]);
    		now.x *= cnt.scale;
    		now.y *= cnt.scale;
    		now.x += cnt.dx;
    		now.y += cnt.dy;
    		if (now == b[i]) continue;
    		++ret;
    		if (ret * 2 > n) return false;
    	}
    
    	return true;
    }
    
    Node solve(int x, int y){
    	Node ret  = {0, 0, 0, 0};
    	ret.cita  = angle(b[y] - b[x]) - angle(a[y] - a[x]);
    	ret.scale = dis(b[x], b[y]) / dis(a[x], a[y]);
    	node cnt  = calc(ret.cita, a[x]);
    	ret.dx    = b[x].x - ret.scale * cnt.x;
    	ret.dy    = b[x].y - ret.scale * cnt.y;
    	return ret;
    }
    
    int main(){
    
    	scanf("%d", &n);
    	rep(i, 1, n){
    		a[i].scan();
    		b[i].scan();
    	}
    
    	if (n == 1){
    		puts("0.000000000000");
    		puts("1.000000000000");
    		node c = b[1] - a[1];
    		c.print();
    		return 0;
    	}
    
    	rep(Case, 1, 100){
    		int x = rand() % n + 1;
    		int y = rand() % n + 1;
    		if (x == y) continue;
    		ret = solve(x, y);
    		if (judge(ret)) break;
    	}
    
    	ret.print();
    	return 0;
    }
    
  • 相关阅读:
    ORACLE 使用笔记
    Python资源大全,让你相见恨晚的Python库
    基于python的k-s值计算
    sklearn聚类模型:基于密度的DBSCAN;基于混合高斯模型的GMM
    skearn学习路径
    透彻形象理解核函数
    LDA降维与PCA降维对比
    sklearn 岭回归
    GBDT、XGBOOST、LightGBM对比学习及调参
    sklearn,交叉验证中的分层抽样
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7532975.html
Copyright © 2020-2023  润新知