zoukankan      html  css  js  c++  java
  • 计算几何

     
    题目链接:https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=5073
    n个正方形,给出每个正方形中心及半径,m次修改(中心与半径)与查询(最近距离),由于给出的区域为x[0,10],y[0,10],直接暴力区间查询即可,注意若为0则直接跳出,否则会t,看别人思路是直接枚举正方形中的每一块分别求min|xi-xj|与min|yi-yj|,但经过画图可知共三种情况如下:
     
    #include <map>
    #include <vector>
    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    #define ull unsigned ll
    #define maxn 100005
    #define maxm 600005
    #define mod 998244353
    using namespace std;
    int t, n, m, len, ans;
    int op, k, x, y, r;
    int X[maxn], Y[maxn], R[maxn];
    
    int solve(int i, int j){
        x = abs(X[i]-X[j]);
        y = abs(Y[i]-Y[j]);
        r = R[i]+R[j];
        if(x < r) //纵向外部重叠
            return y-r;
        else if(y < r) //横向外部重叠
            return x-r;
        int res = x+y-(r<<1); //无外部重叠
        return res;
    }
    int main(){
        scanf("%d", &t);
        while(t--){
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i ++){
                scanf("%d%d%d", X+i, Y+i, R+i);
            }
            int x, y, r;
            while(m--){
                scanf("%d", &op);
                if(op&1){
                    scanf("%d%d%d%d", &k, &x, &y, &r);
                    X[k] = x, Y[k] = y, R[k] = r;
                }else{
                    int res = maxm;
                    scanf("%d%d", &x, &y);
                    for(int i = x; i < y; i ++){
                        for(int j = i+1; j <= y; j ++){
                            res = min(res, solve(i, j));
                            if(res <= 0)break;
                        }
                        if(res <= 0)break;
                    }
                    if(res <= 0)
                        printf("0
    ");
                    else
                        printf("%d
    ", res);
                }
            }
        }
        return 0;
    }
    View Code
     
    点到线段最短距离
    //UVA10263
    %:pragma GCC optimize("Ofast", 2)
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define Inf 0x7fffffff
    #define maxn 1000005
    int t, n, m, len, ans;
    struct Point{
        double x, y;
        double dis(Point& a){ //距离
            return sqrt((x-a.x)*(x-a.x)+(y-a.y)*(y-a.y));
        }
        double dis2(Point& a){ //距离平方
            return (x-a.x)*(x-a.x)+(y-a.y)*(y-a.y);
        }
        double dotprd(Point& a, Point& b){ //点积
            return (x-a.x)*(b.x-a.x)+(y-a.y)*(b.y-a.y);
        }
        double crsprd(Point& a, Point& b){ //叉积
            return (x-a.x)*(b.y-a.y)-(b.x-a.x)*(y-a.y);
        }
    }g[maxn];
    double res;
    Point r, p, temp;
    void solve(Point a, Point b){
        double d = p.dotprd(a, b);
        if(d <= 0){ //向量间构成钝角
            d = p.dis(a);
            if(res > d){
                r = a;
                res = d;
            }
        }else if(d >= a.dis2(b)){ //向量间为锐角,但点与线段一端点构成向量在线段上投影比线段长
            d = p.dis(b);
            if(res > d){
                r = b;
                res = d;
            }
        }else{ //点投影在线段上
            double x = d/a.dis2(b); //线段与投影之比
            temp.x = a.x+x*(b.x-a.x);
            temp.y = a.y+x*(b.y-a.y);
            d = p.dis(temp);
            if(res > d){
                r = temp;
                res = d;
            }
        }
    }
    int main(){
        while(~scanf("%lf%lf%d", &p.x, &p.y, &n)){
            for(int i = 0; i < n+1; i ++){
                scanf("%lf%lf", &g[i].x, &g[i].y);
            }
            res = Inf;
            for(int i = 0; i < n; i ++){
                solve(g[i], g[i+1]);
            }
            printf("%.4lf
    %.4lf
    ", r.x, r.y);
        }
        return 0;
    }
    View Code

     

    三分
    链接:https://ac.nowcoder.com/acm/contest/3006/B
    来源:牛客网

    由于牛牛战队经常要外出比赛,因此在全国各地建立了很多训练基地,每一个基地都有一个坐标(x,y)(x,y)
    这周末,牛牛队又要出去比赛了,各个比赛的赛点都在xx轴上。牛牛战队为了方便比赛,想找一个到达训练基地最大距离最小的地方作为比赛地。
     
    #define EPS 1e-8
    #define mod 1000000007
    double PI = 3.14159265358;
    const int N = 1005;
    int t, n, m, len, ans;
    double add(double a, double b){
        return (fabs(a + b) < EPS * (fabs(a) + fabs(b))) ? 0 : (a + b);
    }
    struct Point {
        double x, y;
        double dist(double a){
            return sqrt(add((x - a)*(x -a) ,(y)*(y) ));
        }
    };
    Point pt[maxn];
    double f(double x){
        int i;
        double Max = 0;
        for( i = 0; i < n;  i++){
            Max = pt[i].dist(x) > Max ? pt[i].dist(x) : Max;
        }
        return Max;
    }
    double tri_search(){
        double Mid, Midmid, L,  R;
        L = -40000.0, R = 40000.0;
        while(L + EPS < R){
            Mid = (L + R) * 0.5;
            Midmid = (Mid + R) *0.5;
            if(f(Mid) <= f(Midmid ))
                R = Midmid;
            else L = Mid;
        }
        return L ;
    }
    int main(){
        while(~scanf("%d", &n) && n){
            for(int i =0 ; i < n; i++)
                scanf("%lf%lf" , &pt[i].x ,&pt[i].y );
            double xx = tri_search();
            double Max = f(xx);
            cout << Max << endl;
        }
        return 0;
    }
    View Code

     

    平面内点构成的的钝角三角形个数

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 500 + 5;
    typedef struct Point {
        ll x, y;
        Point() {}
        Point(ll x, ll y) : x(x), y(y) {}
        Point operator + (Point p) { return Point(x + p.x, y + p.y); }
        Point operator - (Point p) { return Point(x - p.x, y - p.y); }
        ll dot(Point p) { return x * p.x + y * p.y; } // 点积(钝角<0;直角==0;锐角>0)
        ll det(Point p) { return x * p.y - y * p.x; } // 叉积
        bool operator < (const Point& a) const {      // 极角升序
            if (y * a.y <= 0) {
                if (y > 0 || a.y > 0) return y > a.y;
                if (y == 0 && a.y == 0) return x > a.x;
            }
            return x * a.y - y * a.x > 0;
        }
    }Vctor;
    Point node[maxn];
    Vctor vct[maxn * maxn];
    int main(void)
    {
        int n;    
        while (cin >> n) {
            for (int i = 0; i < n; ++i)
                cin >> node[i].x >> node[i].y;
            ll res = 0;
            for (int i = 0; i < n; ++i) {
                ll tot = 0;
                for (int j = 0; j < n; ++j) {
                    if (i == j)        continue;
                    vct[tot++] = node[j] - node[i];
                }
                sort(vct, vct + tot);
                for (int j = 0; j < tot; ++j)    vct[j + tot] = vct[j];    /* 3、4象限按照环类似的处理方式 */
                ll cnt1 = 0, cnt2 = 0;
    
                for (int j = 0; j < tot; ++j) {
                    /*cnt在j左边*/            /* 3、4象限 */
                    while (cnt1 <= j || (cnt1 < j + tot && vct[cnt1].det(vct[j]) < 0) && vct[j].dot(vct[cnt1]) >= 0/*锐角和直角*/) cnt1++;//左边锐角和直角个数(左边最大的非钝角)
                    while (cnt2 <= j || (cnt1 < j + tot && vct[cnt2].det(vct[j]) < 0)) cnt2++;//左边所有角个数(左边最大的角)
                    res += cnt2 - cnt1;
                }
            }
            cout << res << endl;
        }
        return 0;
    }
    View Code

     

    最近点对

    typedef struct{
        double x;
        double y;
    }Point;
    Point A, B;
    vector<Point>vec;//存储点对
    bool cmp_x(Point a, Point b){//x为第一关键字,y为第二关键字排序
        if(a.x == b.x)
            return a.y < b.y;
        return a.x < b.x;
    }
    bool cmp_y(Point a, Point b){//直接以y为关键字排序
        return a.y < b.y;
    }
    double dis(Point a, Point b){
        double x = a.x-b.x;
        double y = a.y-b.y;
        return x*x+y*y;
    }
    //寻找最近点对的点并返回最近距离
    double compare(double d1, double d2, double d3, int l){
        /*三个点vec[l],vec[l+1],vec[l+2],两两比较之间l与l+2用2次,
        于是可以默认存储l与l+2点对,即d2对应的点对,然后与d1与d3比较时
        只需动A或B中的一个即可*/
        if(d1 < d2){
            d2 = d1;
            B = vec[l+1];
        }
        if(d3 < d2){
            d2 = d3;
            A = vec[l+1];
        }
        return d2;
    }
    double ClosestPoints(int l, int r){
        if(r-l == 1){
            A = vec[l], B = vec[l+1];
            return dis(vec[l], vec[l+1]);
        }else if(r-l == 2){
            A = vec[l], B = vec[l+2];//默认d2最小
            double d1 = dis(vec[l], vec[l+1]);
            double d2 = dis(vec[l], vec[l+2]);
            double d3 = dis(vec[l+1], vec[l+2]);
            return compare(d1, d2, d3, l);
        }else{
            int mid = (r+l)/2;
            //从mid为横坐标二分递归
            double min_left = ClosestPoints(l, mid);
            double min_right = ClosestPoints(mid+1, r);
            double d = min(min_left, min_right);
            vector<Point>res;
            for(int i = l; i <= r; i ++){
                if(fabs(vec[i].y-vec[mid].y) < d)
                    res.push_back(vec[i]);
            }
            sort(res.begin(), res.end(), cmp_y);//以y为关键字从小到大排序
            for(int i = 0; i < (int)res.size()-1; i ++){//求取该区间内的最小点对
                for(int j = i+1; j < (int)res.size(); j ++){
                    if(res[j].y-res[i].y >= d)
                        break;
                    double dp = dis(res[i], res[j]);
                    if(dp < d){
                        d = dp;
                        A = res[i];
                        B = res[j];
                    }
                }
            }
            return d;
        }
    }
    
    int main(){
        int N; Point p;
        scanf("%d", &N);
        for(int i = 0; i < N; i ++){
            scanf("%lf%lf", &p.x, &p.y);
            vec.push_back(p);
        }
        sort(vec.begin(), vec.end(), cmp_x);
        ClosestPoints(0, vec.size()-1);
        printf("%.f %.f %.f %.f
    ", A.x, A.y, B.x, B.y);
    }
    View Code

     

    凸包与直线交长

    struct Point{
        double x, y;
        bool operator<(Point a)const{
            if(a.x == x)
                return a.y > y;
            return a.x > x;
        }
    }g[maxn], p[maxn];
    int t, m, n, k, len, flag;
    Point a, b;
    double dis(Point a, Point b){
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    double multy(Point a, Point b, Point c){ //叉乘判线段位置关系
        return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
    }
    Point getIntersect(Point a, Point b, Point c, Point d){ //求直线与边交点
        double per = ((a.x-c.x)*(c.y-d.y)-(c.x-d.x)*(a.y-c.y))/((a.x-b.x)*(c.y-d.y)-(c.x-d.x)*(a.y-b.y));
        a.x += (b.x-a.x)*per;
        a.y += (b.y-a.y)*per;
        return a;
    }
    bool isOnPoint(Point t, Point a, Point b){
        if(multy(t, a, b) == 0.0){
            if((t.x < a.x && t.x < b.x) || (t.x > a.x && t.x > b.x))
                return false;
            if((t.y < a.y && t.y < b.y) || (t.y > a.y && t.y > b.y))
                return false;
            return true;
        }
        return false;
    }
    bool isOnLine(Point a, Point b, Point c, Point d){ //线段互跨
        if(multy(a,c,b)*multy(a,d,b)<=0&&multy(c,a,d)*multy(c,b,d)<=0)
            return true;
        return false;
    }
    bool isIn(Point q){
        Point tmp = q;
        tmp.x = 1e15;
        Point t1, t2;
        int ans = 0;
        for(int i = 0; i < n; i ++){
            t1 = g[i], t2 = g[i+1];
            if(i == n-1)
                t2 = g[0];  //WA点
            if(isOnPoint(q, t1, t2)) //点在边上
                return 1;
            if(fabs(t1.y-t2.y) < EPS)
                continue;
            if(isOnPoint(t1, q, tmp)){ //直线经过点
                if(t1.y > t2.y)
                    ans ++;
            }else if(isOnPoint(t2, q, tmp)){
                if(t2.y > t1.y)
                    ans ++;
            }else if(isOnLine(q, tmp, t1, t2)){ //直线与边相交
                ans ++;
            }
        }
        return ans%2; //奇数在内,偶数在外
    }
    double solve(){
        Point t1, t2;
        int ans = 0, tot = 1;
        for(int i = 0; i < n; i ++){
            t1 = g[i], t2 = g[i+1];
            if(i == n-1)
                t2 = g[0];  //WA点
            if(fabs(multy(a, b, t1)) < EPS && fabs(multy(a, b, t2)) < EPS){ //直线与边重合
                p[ans++] = t1, p[ans++] = t2;
            }else if(multy(a, t1, b)*multy(a, t2, b) <= 0){ //相交
                p[ans++] = getIntersect(a, b, t1, t2);
            }
        }
        if(!ans)
            return 0.00;
        sort(p, p+ans);
        for(int i = 1; i < ans; i ++){ //去重
            t1 = p[i], t2 = p[i-1];
            if(fabs(t1.x-t2.x) < EPS && fabs(t1.y-t2.y) < EPS)
                continue;
            p[tot++] = p[i];
        }
        double sum = 0;
        for(int i = 1; i < tot; i ++){
            t1.x = (p[i].x+p[i-1].x)/2;
            t1.y = (p[i].y+p[i-1].y)/2;
            if(isIn(t1))
                sum += dis(p[i], p[i-1]);
        }
        return sum;
    }
    int main(){
        while(scanf("%d%d", &n, &m) && n+m){
            for(int i = 0; i < n; i ++){
                scanf("%lf%lf", &g[i].x, &g[i].y);
            }
            while(m--){
                scanf("%lf%lf%lf%lf", &a.x, &a.y, &b.x, &b.y);
                printf("%.3lf
    ", solve());
            }
        }
        return 0;
    }
    View Code

     

    卷积模板(NTT)

    //洛谷3803
    int c, n, m, len, ans;
    const ll mod = (119<<23)|1;
    ll a[maxn>>1], b[maxn>>1], rev[maxn];
    ll g = 3, gx = (mod+2)/3;
    void init(){
        ans = 0, len = 1;
        fill(rev, rev+maxn, 0);
    }
    ll qpow(ll a, ll b){
        ll res = 1;
        while(b){
            if(b&1)
                res = res*a%mod;
            a = a*a%mod;
            b >>= 1;
        }
        return res%mod;
    }
    void NTT(ll *p, int c){
        ll x, y, pw;
        for(int i = 0; i < len; i ++){
            if(i < rev[i])
                swap(p[i], p[rev[i]]);
        }
        for(int i = 1; i < len; i <<= 1){
            pw = qpow(c+1?g:gx, (mod-1)/(i<<1));
            for(int j = 0; j < len; j += i<<1){
                ll q = 1;
                for(int k = 0; k < i; k ++, q = q*pw%mod){
                    x = p[j+k], y = q*p[j+k+i]%mod;
                    p[j+k] = (x+y)%mod, p[j+k+i] = (x-y+mod)%mod;
                }
            }
        }
    
    }
    int main(){
        while(~scanf("%d%d", &n, &m)){
            init();
            for(int i = 0; i <= n; i ++)
                scanf("%lld", &a[i]);
            for(int j = 0; j <= m; j ++)
                scanf("%lld", &b[j]);
            while(len <= m+n)
                len <<= 1, ans ++;
            for(int i = 0; i < len; i ++){
                rev[i] = (rev[i>>1]>>1|((i&1)<<(ans-1)));
            }
            NTT(a, 1), NTT(b, 1);
            for(int i = 0; i < len; i ++){
                a[i] = a[i]*b[i]%mod;
            }
            NTT(a, -1);
            ll inv = qpow(len, mod-2);
            for(int i = 0; i <= n+m; i ++){
                printf("%lld ", (a[i]*inv)%mod);
            }
            printf("
    ");
        }
        return 0;
    }
    View Code

     

  • 相关阅读:
    MytBatis错题分析
    Spring核心概念
    延迟与缓存
    MyBatis的关联查询
    Mabatis注解
    [leetcode]226. Invert Binary Tree翻转二叉树
    [leetcode]633. Sum of Square Numbers平方数之和
    [leetcode]296. Best Meeting Point最佳见面地点
    [leetcode]412. Fizz Buzz报数
    [leetcode]142. Linked List Cycle II找出循环链表的入口
  • 原文地址:https://www.cnblogs.com/microcodes/p/12319269.html
Copyright © 2011-2022 走看看