zoukankan      html  css  js  c++  java
  • 模板

    这个是正确的算法,但是复杂度可能会卡到 (O(n^2)) ,加上每个点最多匹配的临近点最多15个/30个限制的话复杂度就可以保证了,最多就再做一次增加正确的几率,我确实不行从头到尾都是随机的怎么有人卡得掉。

    #include<bits/stdc++.h>
    using namespace std;
    
    const double PI = acos(-1.0);
    
    struct Point {
        double x, y;
    } p[200000 + 5];
    
    int n;
    
    inline double RandomDouble() {
        return 1.0 * rand() / RAND_MAX;
    }
    
    inline bool cmp(const Point &a, const Point &b) {
        return a.x < b.x;
    }
    
    inline double dis(const Point &a, const Point &b) {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    double Calc(const double &A, double d) {
        double x0 = -1e9 + 2e9 * RandomDouble(), y0 = -1e9 + 2e9 * RandomDouble(); //随机弄一个旋转原点
        double cosA = cos(A), sinA = sin(A);
        double xc = -x0 * cosA + y0 * sinA + x0;
        double yc = -x0 * sinA - y0 * cosA + y0;
        //利用图形学的知识加速
        for(int i = 1; i <= n; i++) {
            double x = p[i].x, y = p[i].y;
            //p[i].x = (x - x0) * cosA - (y - y0) * sinA + x0;
            //p[i].y = (x - x0) * sinA + (y - y0) * cosA + y0;
            p[i].x = x * cosA - y * sinA + xc;
            p[i].y = x * sinA + y * cosA + yc;
        }
        sort(p + 1, p + 1 + n, cmp);
    
        for(int i = 1; i <= n; i++) {
            for(int j = i + 1; j <= n /*&& j <= i + 15*/ && p[j].x - p[i].x < d; j++)
                d = min(d, dis(p[i], p[j]));
        }
        return d;
    }
    
    int main() {
        srand(time(0));
    
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%lf%lf", &p[i].x, &p[i].y);
    
        double d = 1e36;
        d = Calc(RandomDouble() * 2.0 * PI, d);
        //d = Calc(RandomDouble() * 2.0 * PI, d);
        printf("%.4f
    ", d);
        return 0;
    }
    

    分治算法,虽然每一层里面都排序,但实际上选出的点并不多。

    #include<bits/stdc++.h>
    using namespace std;
    
    const double INF = 1e36;
    
    const int MAXN = 200000;
    
    int n, tmp[MAXN];
    struct Point {
        double x, y;
    } S[MAXN + 5];
    
    bool cmpx(const Point &a, const Point&b) {
        return a.x < b.x;
    }
    
    bool cmpidy(const int &a, const int &b) {
        return S[a].y < S[b].y ;
    }
    
    inline double min(const double &a, const double &b) {
        return a < b ? a : b;
    }
    
    inline double dist(const int &i, const int &j) {
        return sqrt((S[i].x - S[j].x) * (S[i].x - S[j].x) + (S[i].y - S[j].y) * (S[i].y - S[j].y));
    }
    
    double merge(int left, int right) {
        double d = INF;
        if(left == right)
            return d ;
        if(left + 1 == right)
            return dist(left, right);
        int mid = left + right >> 1;
        double d1 = merge(left, mid) ;
        double d2 = merge(mid + 1, right) ;
        d = min(d1, d2);
        int i, j, k = 0;
        for(i = left; i <= right; i++)
            if(fabs(S[mid].x - S[i].x) <= d)
                tmp[++k] = i;
        sort(tmp + 1, tmp + k + 1, cmpidy);
        for(i = 1; i <= k; i++)
            for(j = i + 1; j <= k && S[tmp[j]].y - S[tmp[i]].y < d; j++) {
                double d3 = dist(tmp[i], tmp[j]);
                if(d > d3)
                    d = d3;
            }
        return d;
    }
    
    int main() {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%lf%lf", &S[i].x, &S[i].y);
        sort(S + 1, S + n + 1, cmpx);
        printf("%.4f
    ", merge(1, n));
        return 0;
    }
    

    效率更高的随机算法,但是不能保证正确性因为只取了至多后10个点,假如把这个去掉又有可能被卡成T,不过从旋转角到旋转原点都是完全随机的,多试几次可能就行了,假如不放心的话可以多Calc几次。
    假如取至多后20个点的话应该是极限了,假如后20个点都过不了宁愿再重新Calc一次吧。

    #include<bits/stdc++.h>
    using namespace std;
    
    const double PI = acos(-1.0);
    
    struct Point {
        double x, y;
    } p[200000 + 5];
    
    int n;
    
    inline double RandomDouble() {
        return 1.0 * rand() / RAND_MAX;
    }
    
    inline bool cmp(const Point &a, const Point &b) {
        return a.x < b.x;
    }
    
    inline double dis(const Point &a, const Point &b) {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    double Calc(const double &A) {
        double x0 = -10.0 + 20.0 * RandomDouble(), y0 = -10.0 + 20.0 * RandomDouble(); //随机弄一个旋转原点
        for(int i = 1; i <= n; i++) {
            double x = p[i].x, y = p[i].y, xn, yn;
            xn = (x - x0) * cos(A) - (y - y0) * sin(A) + x0 ;
            yn = (x - x0) * sin(A) + (y - y0) * cos(A) + y0 ;
            p[i].x = xn;
            p[i].y = yn;
        }
        sort(p + 1, p + 1 + n, cmp);
    
        double d = 1e36;
        for(int i = 1; i <= n; i++) {
            for(int j = i + 1; j <= n && j <= i + 10 && p[j].x - p[i].x < d; j++)
                d = min(d, dis(p[i], p[j]));
        }
        return d;
    }
    
    int main() {
        srand(time(0));
    
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%lf%lf", &p[i].x, &p[i].y);
    
        printf("%.4f
    ", Calc(RandomDouble() * 2.0 * PI));
        return 0;
    }
    

    类似这样?

    #include<bits/stdc++.h>
    using namespace std;
    
    const double PI = acos(-1.0);
    
    struct Point {
        double x, y;
    } p[200000 + 5];
    
    int n;
    
    inline double RandomDouble() {
        return 1.0 * rand() / RAND_MAX;
    }
    
    inline bool cmp(const Point &a, const Point &b) {
        return a.x < b.x;
    }
    
    inline double dis(const Point &a, const Point &b) {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    double Calc(const double &A, double d) {
        double x0 = -1e9 + 2e9 * RandomDouble(), y0 = -1e9 + 2e9 * RandomDouble(); //随机弄一个旋转原点
        for(int i = 1; i <= n; i++) {
            double x = p[i].x, y = p[i].y, xn, yn;
            xn = (x - x0) * cos(A) - (y - y0) * sin(A) + x0 ;
            yn = (x - x0) * sin(A) + (y - y0) * cos(A) + y0 ;
            p[i].x = xn;
            p[i].y = yn;
        }
        sort(p + 1, p + 1 + n, cmp);
    
        for(int i = 1; i <= n; i++) {
            for(int j = i + 1; j <= n && j <= i + 15 && p[j].x - p[i].x < d; j++)
                d = min(d, dis(p[i], p[j]));
        }
        return d;
    }
    
    int main() {
        srand(time(0));
    
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%lf%lf", &p[i].x, &p[i].y);
    
        double d = 1e36;
        d = Calc(RandomDouble() * 2.0 * PI, d);
        d = Calc(RandomDouble() * 2.0 * PI, d);
        printf("%.4f
    ", d);
        return 0;
    }
    

    卡了一下常数,有很多多余的浮点运算。假如把至多后15个点的限制去掉正确性就可以保证了,但是复杂度可能会爆炸,不过这样子就只需要计算一次就可以了。

    #include<bits/stdc++.h>
    using namespace std;
    
    const double PI = acos(-1.0);
    
    struct Point {
        double x, y;
    } p[200000 + 5];
    
    int n;
    
    inline double RandomDouble() {
        return 1.0 * rand() / RAND_MAX;
    }
    
    inline bool cmp(const Point &a, const Point &b) {
        return a.x < b.x;
    }
    
    inline double dis(const Point &a, const Point &b) {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    double Calc(const double &A, double d) {
        double x0 = -1e9 + 2e9 * RandomDouble(), y0 = -1e9 + 2e9 * RandomDouble(); //随机弄一个旋转原点
        double cosA = cos(A), sinA = sin(A);
        double xc = -x0 * cosA + y0 * sinA + x0;
        double yc = -x0 * sinA - y0 * cosA + y0;
        //利用图形学的知识加速
        for(int i = 1; i <= n; i++) {
            double x = p[i].x, y = p[i].y, xn, yn;
            //p[i].x = (x - x0) * cosA - (y - y0) * sinA + x0;
            //p[i].y = (x - x0) * sinA + (y - y0) * cosA + y0;
            p[i].x = x * cosA - y * sinA + xc;
            p[i].y = x * sinA + y * cosA + yc;
        }
        sort(p + 1, p + 1 + n, cmp);
    
        for(int i = 1; i <= n; i++) {
            for(int j = i + 1; j <= n /*&& j <= i + 15*/ && p[j].x - p[i].x < d; j++)
                d = min(d, dis(p[i], p[j]));
        }
        return d;
    }
    
    int main() {
        srand(time(0));
    
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
            scanf("%lf%lf", &p[i].x, &p[i].y);
    
        double d = 1e36;
        d = Calc(RandomDouble() * 2.0 * PI, d);
        //d = Calc(RandomDouble() * 2.0 * PI, d);
        printf("%.4f
    ", d);
        return 0;
    }
    
  • 相关阅读:
    PAT (Advanced Level) Practice 1071 Speech Patterns (25分)
    PAT (Advanced Level) Practice 1070 Mooncake (25分)
    PAT (Advanced Level) Practice 1069 The Black Hole of Numbers (20分)
    PAT (Advanced Level) Practice 1074 Reversing Linked List (25分)
    PAT (Advanced Level) Practice 1073 Scientific Notation (20分)
    第一次冲刺个人总结01
    构建之法阅读笔记01
    人月神话阅读笔记01
    四则运算2
    学习进度条(软件工程概论1-8周)
  • 原文地址:https://www.cnblogs.com/Inko/p/11516098.html
Copyright © 2011-2022 走看看