【计几】三维凸包题集


The Worm in the Apple【三维凸包内一点到凸包表面的最短距离】

题意:求三维凸包内一点到凸包表面的最短距离。

思路:最优解一定存在于点到凸包面所在平面的距离中。

证明:

  • 根据点在平面上的投影是否落在凸包面内,可将凸包面分为两种。

  • 假设点在凸包面A所在平面的投影落在外面,那一定存在某相邻凸包面B,使得两平面夹角大于90°。

  • 过此点和两投影点作横截面,发现dis(点,凸包面A) < dis(点,凸包面所在平面) < dis(点,相邻凸包面B)

  • 因此点到第一种凸包面的距离总小于到第二种凸包面的距离。枚举点到所有平面距离即可。

拓展:三维凸包外一点到凸包表面的最短距离不满足以上性质,最优解也可能位于凸包棱上。

AC代码:http://acm.hdu.edu.cn/viewcode.php?rid=36763472


Throw the Stones【询问最大增量】

题意:询问增量过程中最大增量。

未AC代码:

de不出来bug,de不出来bug,de不出来bug

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<bitset>
using namespace std;

typedef long long LL;
const int N = 1e4 + 10;
const double eps = 1e-12;

double rand_eps() { return ((double)rand() / RAND_MAX - 0.5) * eps; }

struct point{
    double x, y, z;
    
    void shake() { x += rand_eps(); y += rand_eps(); z += rand_eps(); }
}P[N];

point operator + (point a, point b) { return {a.x + b.x, a.y + b.y, a.z + b.z}; }
point operator - (point a, point b) { return {a.x - b.x, a.y - b.y, a.z - b.z}; }
point cross(point a, point b) { return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; }
double dot(point a, point b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
double length(point a) { return sqrt(a.x * a.x + a.y * a.y + a.z * a.z); }
double volume(point a, point b, point c, point d) { return dot(cross(b - a, c - a), d - a); }

struct plane{
    int v[3];
    
    point norm() { return cross(P[v[1]] - P[v[0]], P[v[2]] - P[v[0]]); }
    double area() { return length(norm()) / 2; }
    bool above(point a) { return dot(a - P[v[0]], norm()) >= 0; }
    
}E[N], tmp[N];



int n, m;
bitset<N>g[N];
double ans;
int id;

void get_convex_3d()
{
    m = 0;
    E[m++] = {0, 1, 2}; E[m++] = {2, 1, 0};
    double last = 0;
    for(int i=3; i<n; i++)
    {
        int cnt = 0;
        for(int j=0; j<m; j++)
        {
            bool t = E[j].above(P[i]);
            if(!t) tmp[cnt++] = E[j];
            for(int k=0; k<3; k++)
                g[E[j].v[k]][E[j].v[(k + 1) % 3]] = t;
        }
        for(int j=0; j<m; j++)
            for(int k=0; k<3; k++)
            {
                int a = E[j].v[k], b = E[j].v[(k + 1) % 3];
                if(g[a][b] && !g[b][a]) tmp[cnt++] = {a, b, i};
            }
            
        m = cnt;
        for(int j=0; j<m; j++) E[j] = tmp[j];
        
        double now = 0;
        for(int j=0; j<m; j++) now += volume(P[E[j].v[0]], P[E[j].v[1]], P[E[j].v[2]], {0, 0, 0});
        now = fabs(now);
        
        if(ans < now - last) ans = now - last, id = i + 1, last = now;
    }
    
}


int main()
{
	
    int T = 1;
    while(scanf("%d", &n)!=EOF)
    {
        for(int i=0; i<n; i++)
        {
            scanf("%lf %lf %lf", &P[i].x, &P[i].y, &P[i].z);
            P[i].shake();
        }

        ans = 0;

        get_convex_3d();

        printf("Case #%d:\n%d %.2f\n", T++, id, ans / 6);
    }


    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值