首页 > 代码库 > 训练日志

训练日志

计算几何学习进入了一个瓶颈啊 = =

有些偏难的东西进展很缓慢 加上最近做题类型确实单一 导致比赛的时候经常写跪

所以打算慢慢进展计算几何内容 每天都做一些常规的

 

先说下计算几何的情况

进入了扫描线部分 和之前普通的矩形周长并啥的画风完全不同了

目前搞出来的东西也挺少

HDU 3124

给你一些平面上不相交的圆 圆上的点的最近距离

平面最近点对有固定套路 但是放到圆上还有半径 不能套用(但据说现场有人考最近点对的做法搞过去了?)

 

求最近距离 考虑二分 剩下的就是快速判断圆是否相交

我们考虑扫描线 如果是对圆的左右垂直切线离散

左侧加入集合 右侧从集合中删除 那么相交会在某个时刻 集合内的圆中产生

而当x左边满足相交条件 一定是一段y中产生交点

所以我们考虑对所有点y排序 按照上述规则假如set

在插入和删除时检查相切就可以了

 

仅在插入时检查是存在问题的

如hdu上给的

-10 20 1

0 0 10

30 40 39

答案应该是后两个圆产生的1 但是如果仅在插入时判断 圆1会干扰结果

在圆1删除时 2 3重新相邻 应再更新答案

 

HDU 3662

三维凸包上面的个数

模板题了

三维凸包是一种增量算法

首先找出四个不共面的顶点组成一个四面体

逐个插入点p

如果p在当前凸包内 凸包不改变

如果p在凸包外 那么所有能p“看见”的面都应该被更新

用有向体积来判断点与面的关系

记录所选的面(若干个三角形) 每条边对应的面(边有方向的)

时间复杂度O(n^2)的

好像明白了道理也不会写 然后就照着xiaotiantang学长的代码码了一发

技术分享
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
const int N = 550;

struct Point{
    double x, y, z;
    Point(){}
    Point(double _, double __, double ___):
        x(_), y(__), z(___) {}
    Point operator - (const Point p) const{return Point (x - p.x, y - p.y, z - p.z);}
    Point operator + (const Point p) const{return Point (x + p.x, y + p.y, z + p.z);}
    Point operator / (const double p) const{return Point (x / p, y / p, z / p);}
    Point operator ^ (const Point p) const{return Point (y * p.z - z * p.y, z * p.x - x * p.z, x * p.y - y * p.x);}
    Point operator * (const double t) const{return Point(x * t, y * t, z * t);}
    double operator * (const Point p) const{return x * p.x + y * p.y + z * p.z;}
};

double abs(Point  p){return sqrt(p * p);}

struct ConvexHull3D{
    struct Facet{
        int a, b, c;
        bool flag;
    };
    int n;
    Point pt[N];
    int tri_num;
    Facet face[8 * N];
    int g[N][N];
    
    Point Cross(const Point & a, const Point & b, const Point & c){
        return (b - a) ^ (c - a);
    }
    
    double tri_area(Point a, Point b, Point c){
        return abs(Cross(c, a, b)) / 2;
    }
    
    double tetrahedron_volume(Point a, Point b, Point c, Point d){
        return (((b - a) ^ (c - a)) * (d - a)) / 6;
    }
    
    double dlcmp(Point & p, Facet & f){
        Point m = pt[f.b] - pt[f.a],
              n = pt[f.c] - pt[f.a],
              t = p - pt[f.a]; 
        return (m ^ n) * t;
    }
    
    void deal(int a, int b, int p){
        int f = g[a][b];
        Facet add;
        if(face[f].flag){
            if(dlcmp(pt[p], face[f]) > eps)
                dfs(p, f);
            else{
                add.a = b;
                add.b = a;
                add.c = p;
                add.flag = 1;
                g[p][b] = g[a][p] = g[b][a] = tri_num;
                face[tri_num ++] = add;
            }
        }
    }
    
    void dfs(int p, int now){
        face[now].flag = 0;
        deal(face[now].b, face[now].a, p);
        deal(face[now].c, face[now].b, p);
        deal(face[now].a, face[now].c, p);
    }
    
    bool same(int s, int t){
        Point & a = pt[face[s].a];
        Point & b = pt[face[s].b];
        Point & c = pt[face[s].c];
        bool res = fabs(tetrahedron_volume(a, b, c, pt[face[t].a])) < eps 
                && fabs(tetrahedron_volume(a, b, c, pt[face[t].b])) < eps
                && fabs(tetrahedron_volume(a, b, c, pt[face[t].c])) < eps;
        return res;
    }
    
    void solve(){
        int i, j, tmp;
        Facet add;
        bool flag;
        tri_num = 0;
        if(n < 4) return;
        flag = 1;
        for(i = 1; i < n; i ++)
            if(abs((pt[0] - pt[1]) ^ (pt[1] - pt[i])) > eps){
                swap(pt[2], pt[i]);
                flag = 0;
                break;
            }
        if(flag) return;
        flag = 1;
        for(int i = 2; i < n; i ++){
            if(fabs( ((pt[0] - pt[1]) ^ (pt[1] - pt[2])) * (pt[0] - pt[i]) ) > eps){
                swap(pt[3], pt[i]);
                flag = 0;
                break;
            }
        }
        if(flag) return;
        flag = 1;
        for(int i = 3; i < n; i ++)
            if(abs(pt[0] - pt[i]) > eps){
                swap(pt[1], pt[i]);
                flag = 0;
                break;
            }
        if(flag) return;
        for(int i = 0; i < 4; i ++){
            add.a = (i + 1) % 4;
            add.b = (i + 2) % 4;
            add.c = (i + 3) % 4;
            add.flag = 1;
            if(dlcmp(pt[i], add) > 0)
                swap(add.b, add.c);
            g[add.a][add.b] = g[add.b][add.c] = g[add.c][add.a] = tri_num;
            face[tri_num ++] = add;
        }
        
        for(i = 4; i < n; i ++)
            for( j = 0; j < tri_num; j ++)
                if(face[j].flag && dlcmp(pt[i], face[j]) > eps){
                    dfs(i, j);
                    break;
                }
        
        tmp = tri_num;
        for(i = tri_num = 0; i < tmp; i ++)
            if(face[i].flag) face[tri_num ++] = face[i];
    }
    
    double area(){
        double res = 0;
        if(n == 3)
            res = abs(Cross(pt[0], pt[1], pt[2])) / 2;
        else if(!tri_num){
            for(int i = 0; i < n; i ++)
                res += abs(pt[i] ^ pt[(i + 1) % n]);
            res = fabs(res);
        }
        else{
            for(int i = 0; i < tri_num; i ++)
                res += tri_area(pt[face[i].a], pt[face[i].b], pt[face[i].c]);
        }
        return res;
    }
    
    double volume(){
        double res = 0;
        Point tmp(0, 0, 0);
        for(int i = 0; i < tri_num; i ++)
            res += tetrahedron_volume(tmp, pt[face[i].a], pt[face[i].b], pt[face[i].c]);
        return fabs(res);
    }
    
    Point get_center(){//重心 
        Point res(0, 0, 0), o(0, 0, 0), p;
        double sum = 0, vol;
        for(int i = 0; i < tri_num; i ++){
            vol = tetrahedron_volume(o, pt[face[i].a], pt[face[i].b], pt[face[i].c]);
            sum += vol;
            p = (o + pt[face[i].a] + pt[face[i].b] + pt[face[i].c]) * vol / 4;
            res = res + p;
        }
        res = res / sum;
        return res;
    }
    
    int triangle_num(){
        return tri_num;
    }
    
    int polygon_num(){
        int i, j, res, flag;
        res = 0;
        for(i = 0; i < tri_num; i ++){
            flag = 1;
            for(j = 0; j < i; j ++)
                if(same(i, j)){
                    flag = 0;
                    break;
                }
            res += flag;
        }
        return res;
    }
};

ConvexHull3D hull;
double PFD(Point p, Point a, Point b, Point c){
    Point vec = (b - a) ^ (c - a);
    Point t = a - p;
    double tmp = (vec * t) / (abs(vec));
    return fabs(tmp);
}


int main(){
    //freopen("enwrap.in", "r", stdin);
    //freopen("enwrap.out", "w", stdout);
    scanf("%d", &hull.n);
    for(int i = 0; i < hull.n; i ++)
        scanf("%lf%lf%lf", &hull.pt[i].x, &hull.pt[i].y, &hull.pt[i].z);
    hull.solve();
    printf("%.6lf\n", hull.tri_num);
    return 0;
}
View Code

代码还是比较好理解的 自己实现估计会很麻烦 当成板子吧

 

还有一道题 atcoder 069 E

给你一个偶数长的排列 你每次可以取出相邻的两个元素 保持原来的顺序扔到另一个初始为空的队列的队首 直到原序列空

问你新队列字典序最小是什么

 

sb了一发 被潘学姐嘲笑 肯定会想着倒过来考虑 想每次找合法的最小从左到右放置起来

对于一个偶数长的串LR 肯定取一个奇数下标l为第一个 后面的偶数下标r为第二个

这样序列又被划分成三各偶数串 [L,l -1], [l +1,r - 1], [r + 1,R]递归下去 (相对的下标已经更新了 但每次都是奇数开头 偶数结尾)

每次找最小就可以了

这样会有一种拓扑关系 也有字典序最小的限制 所以 用优先队列维护 每次找最小用ST  可以做到nlogn

但是我太懒了 = = 就写了zkw nlog^2n 跑的也不慢

 

其他的题目就当是练手的。。。但是简单的题目也出现了可怕的错误= =

还是要通过平时多敲来避免啊

 

其实在看一个多边形嵌套的扫描线问题 但想不明白

也打算开随机化算法的部分了 不是很着急(大概) 

平时水题常规题也要做 训练加油吧

训练日志