UVa11887 Tetrahedrons and Spheres

UVa11887 Tetrahedrons and Spheres

  • 题目链接
  • 题意
  • 分析
  • AC 代码

题目链接

    本题是2010年湖南省第六届大学生计算机程序设计竞赛的K题

题意

    三维空间中有a个四面体和b个球(1≤a,b≤5),求它们体积的并(重叠部分体积只累加一次)。所有坐标为绝对值不超过5的整数,球的半径ri≤3。

分析

    肯定要用到数值积分,用自适应辛普森法来求,主要还是看按z值切片后的平面问题该怎么处理:如何求三角形、四边形、圆的面积并。​
    如果没有圆,求多边形的面积,可以用梯形剖分的思想来处理:假设多边形的顶点是逆时针顺序给出的,遍历每条边时,如果顶点是从左到右的(横坐标从小到大)就把两个顶点之间与过最低点的水平线组成的一个直角梯形作为负面积,相反从右往左则把构成的直角梯形作为正面积,然后用正面积减掉负面积就可以得到多边形的面积。
    要求所有多边形的面积并,则需要找出所有的梯形分割点:多边形本身的顶点横坐标和多边形相交产生的点的横坐标。分割点排序后,逐段( [ x a − 1 , x a ] [x_{a-1},x_a] [xa1,xa])对多边形切割得出所有的正负梯形,再求面积并。
   细说一下逐段( [ x a − 1 , x a ] [x_{a-1},x_a] [xa1,xa])求面积并的处理过程:先把梯形斜边按位置关系从上到下排序(一般用梯形斜边的中点的高度来比大小),正/负面积梯形有一个符号标识 f i f_i fi(取值 ± 1 \pm1 ±1),面积记录一个正值(实际上记录梯形斜边中点的高度 h i h_i hi),初始计数标识 c n t = 0 cnt=0 cnt=0以及面积结果为0,遍历梯形时如果 c n t > 0 cnt>0 cnt>0则面积累加 ( x a − x a − 1 ) × ( h i − 1 − h i ) (x_a-x_{a-1})\times (h_{i-1}-h_i) (xaxa1)×(hi1hi),再更新 c n t = c n t + f i cnt=cnt+f_i cnt=cnt+fi
   其实对这种方法稍加改造就能处理有圆的情况:分割点加入圆心以及圆的左右端点、圆与圆交点以及多边形与圆交点的横坐标,再逐段切割多变形和圆,切割圆时同样找出正负梯形部分并求出梯形斜边与圆弧那部分的面积 a i a_i ai,再把梯形斜边中点竖直向外延伸至与圆相交处的高度作为排序依据。同样在遍历时如果 c n t > 0 cnt>0 cnt>0则对面积进行累加,累加量变成: ( x a − x a − 1 ) × ( h i − 1 − h i ) + a i − 1 × f i − 1 − a i × f i (x_a-x_{a-1})\times (h_{i-1}-h_i)+a_{i-1}\times f_{i-1}-a_i\times f_i (xaxa1)×(hi1hi)+ai1×fi1ai×fi
   可以设想一下多边形和圆相交的各种情况,画一个分割后的图模拟并深入理解一下这个过程。
   还有一个更简洁高效也更直观的处理方式:将梯形从上到下排序后,对各连通部分找出最上最下两个梯形就能得出此部分面积为$ ( x a − x a − 1 ) × ( h i − h j ) + a i + a j (x_a-x_{a-1})\times (h_{i}-h_j)+a_i+a_j (xaxa1)×(hihj)+ai+aj
   给一份测试数据。
   最后附两个梯形剖分相关的RMQ问题:
   梯形剖分入门(特殊情况)【ice】
   考试B 冰雪奇缘改版 多边形剖梯形+线段树维护区间

AC 代码

#include <iostream>
#include <iomanip>
#include <cmath>
#include <algorithm>
using namespace std;

#define eps 1e-12
#define M 335
#define N 5
int x[N][4], y[N][4], z[N][4], cx[N], cy[N], cz[N], r[N], c[N], a, b, m, t;
double px[N][5], py[N][5], sx[M], cr[N];

double interp(double x1, double y1, double x2, double y2, double x) {
    return (y1*(x2-x) + y2*(x-x1)) / (x2-x1);
}

void cross(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
    double dx = x2-x1, dy = y2-y1, dx1 = x3-x1, dy1 = y3-y1, dx2 = x4-x1, dy2 = y4-y1;
    if ((dx*dy1-dx1*dy)*(dx*dy2-dx2*dy) >= 0.) return;
    dx = x4-x3; dy = y4-y3; dx1 = x1-x3; dy1 = y1-y3; dx2 = x2-x3; dy2 = y2-y3;
    double c1 = dx*dy1-dx1*dy, c2 = dx*dy2-dx2*dy;
    if (c1*c2 >= 0.) return;
    c1 /= c1 - c2; sx[t++] = (1-c1)*x1 + c1*x2;
}

void cross(double x1, double y1, double x2, double y2, int i) {
    double dx = x2-x1, dy = y2-y1, l = sqrt(dx*dx + dy*dy);
    if (l < eps) return;
    double vx = cx[i]-x1, vy = cy[i]-y1; dx /= l; dy /= l;
    double d = abs(dx*vy-vx*dy);
    if (d > cr[i]-eps) return;
    double p = dx*vx+dy*vy, q = sqrt(cr[i]*cr[i]-d*d), p1 = p-q, p2 = p+q;
    if (p1 > -eps && p1 < l+eps) sx[t++] = x1 + dx*p1;
    if (p2 > -eps && p2 < l+eps) sx[t++] = x1 + dx*p2;
}

void cross(int i, int j) {
    double dx = cx[i]-cx[j], dy = cy[i]-cy[j], d = sqrt(dx*dx + dy*dy);
    if (d > cr[i]+cr[j]-eps || d < abs(cr[i]-cr[j])+eps) return;
    double cosa = dx/d, cosb = (cr[j]*cr[j]+d*d-cr[i]*cr[i])/2./cr[j]/d, ss = dy/d*sqrt(1-cosb*cosb), cc = cosa*cosb;
    sx[t++] = cx[j]+cr[j]*(cc-ss); sx[t++] = cx[j]+cr[j]*(cc+ss);
}

struct trap {
    double h, t, a; int f;
    bool operator< (const trap& rhs) const {
        return t > rhs.t;
    }
} s[N<<2];

void trap(int i, double l, double r) {
    int cc = 0; double h[2];
    for (int j=0; j<c[i]; ++j) {
        double x1 = px[i][j], y1 = py[i][j], x2 = px[i][j+1], y2 = py[i][j+1];
        if (min(x1,x2) > l+eps || max(x1,x2) < r-eps) continue;
        h[cc++] = .5 * (interp(x1, y1, x2, y2, l) + interp(x1, y1, x2, y2, r));
    }
    if (cc != 2) return;
    if (h[0] < h[1]) h[0] += h[1], h[1] = h[0]-h[1], h[0] = h[0]-h[1];
    s[m].h = h[0]; s[m].t = h[0]; s[m].a = 0.; s[m++].f = 1; s[m].h = h[1]; s[m].t = h[1]; s[m].a = 0.; s[m++].f = -1;
}

void trapc(int i, double l, double r) {
    if (max(abs(l-cx[i]), abs(r-cx[i])) > cr[i]+eps) return;
    double d1 = cr[i]*cr[i]-(l-cx[i])*(l-cx[i]), d2 = cr[i]*cr[i]-(r-cx[i])*(r-cx[i]);
    d1 = d1<=0. ? 0. : sqrt(d1); d2 = d2<=0. ? 0. : sqrt(d2);
    double x = .5 * (l+r), d = cr[i]*cr[i]-(x-cx[i])*(x-cx[i]); d = d<=0. ? 0. : sqrt(d);
    double ds = ((l-r)*(l-r) + (d1-d2)*(d1-d2)) / 4., h = sqrt(cr[i]*cr[i]-ds); ds = sqrt(ds);
    double a = cr[i]*cr[i]*asin(ds/cr[i]) - ds*h;
    s[m].h = cy[i] + .5 * (d1 + d2); s[m].t = cy[i] + d; s[m].a = a; s[m++].f = 1;
    s[m].h = cy[i] - .5 * (d1 + d2); s[m].t = cy[i] - d; s[m].a = a; s[m++].f = -1;
}

double area(double h) {
    for (int i=t=0; i<a; ++i) {
        for (int j=c[i]=0; j<4; ++j) {
            if (z[i][j] == h) {
                px[i][c[i]] = x[i][j]; py[i][c[i]++] = y[i][j]; continue;
            }
            for (int k=j+1; k<4; ++k) if (z[i][k] != h) {
                int e = min(z[i][j], z[i][k]), f = max(z[i][j], z[i][k]);
                if (e==f || f<h || e>h) continue;
                px[i][c[i]] = interp(z[i][j], x[i][j], z[i][k], x[i][k], h);
                py[i][c[i]++] = interp(z[i][j], y[i][j], z[i][k], y[i][k], h);
            }
        }
        if (c[i] < 3) continue;
        for (int j=0; j<c[i]; ++j) sx[t++] = px[i][j];
        if (c[i] == 4) {
            double dx = px[i][2] - px[i][0], dy = py[i][2] - py[i][0],
                dx1 = px[i][1] - px[i][0], dy1 = py[i][1] - py[i][0],
                dx2 = px[i][3] - px[i][0], dy2 = py[i][3] - py[i][0], p;
            if ((dx*dy1-dx1*dy)*(dx*dy2-dx2*dy) > 0.) {
                if ((dx1*dy-dx*dy1)*(dx1*dy2-dx2*dy1) > 0.) {
                    p = px[i][1]; px[i][1] = px[i][2]; px[i][2] = px[i][3]; px[i][3] = p;
                    p = py[i][1]; py[i][1] = py[i][2]; py[i][2] = py[i][3]; py[i][3] = p;
                } else
                    p = px[i][2], px[i][2] = px[i][1], px[i][1] = p, p = py[i][2], py[i][2] = py[i][1], py[i][1] = p;
            }
        }
        px[i][c[i]] = px[i][0]; py[i][c[i]] = py[i][0];
    }
    for (int i=0; i<b; ++i) {
        cr[i] = r[i]*r[i] - (cz[i]-h)*(cz[i]-h); cr[i] = cr[i]<=0. ? 0. : sqrt(cr[i]);
        if (cr[i] <= eps) continue;
        sx[t++] = cx[i]; sx[t++] = cx[i]-cr[i]; sx[t++] = cx[i]+cr[i];
    }
    for (int i=0; i<a; ++i) if (c[i] > 2) for (int j=0; j<c[i]; ++j) {
        for (int k=i+1; k<a; ++k) if (c[k] > 2) for (int p=0; p<c[k]; ++p)
            cross(px[i][j], py[i][j], px[i][j+1], py[i][j+1], px[k][p], py[k][p], px[k][p+1], py[k][p+1]);
        for (int k=0; k<b; ++k) if (cr[k] > eps) cross(px[i][j], py[i][j], px[i][j+1], py[i][j+1], k);
    }
    for (int i=0; i<b; ++i) if (cr[i] > eps) for (int j=i+1; j<b; ++j) if (cr[j] > eps) cross(i, j);
    sort(sx, sx+t);
    double ans = 0., d;
    for (int i=1; i<t; ++i) if ((d = sx[i]-sx[i-1]) > eps) {
        for (int j=m=0; j<a; ++j) if (c[j] > 2) trap(j, sx[i-1], sx[i]);
        for (int j=0; j<b; ++j) if (cr[j] > eps) trapc(j, sx[i-1], sx[i]);
        sort(s, s+m);
        for (int j=0, cc=0, p; j<m; ++j) {
            if (cc == 0) p = j;
            if ((cc += s[j].f) == 0) ans += d * (s[p].h-s[j].h) + s[p].a + s[j].a;
        }
    }
    return ans;
}

double asr(double l, double m, double r, double fl, double fm, double fr, double ans, double err, int step) {
    double lm = (l+m)/2., flm = area(lm), sl = (fl + 4.*flm + fm) * (m-l) / 6.,
        rm = (m+r)/2., frm = area(rm), sr = (fm + 4.*frm + fr) * (r-m) / 6.;
    if (abs(sl+sr-ans) <= 15.*err && step < 0) return sl + sr + (sl+sr-ans) / 15.;
    return asr(l, lm, m, fl, flm, fm, sl, err/2., step-1) + asr(m, rm, r, fm, frm, fr, sr, err/2., step-1);
}

double asr(double l, double r, double err) {
    double m = (l+r)/2., fl = area(l), fm = area(m), fr = area(r);
    return asr(l, m, r, fl, fm, fr, (fl + 4.*fm + fr) * (r-l) / 6., err, 6);
}

void solve() {
    for (int i=0; i<a; ++i) for (int j=0; j<4; ++j) cin >> x[i][j] >> y[i][j] >> z[i][j];
    for (int i=0; i<b; ++i) cin >> cx[i] >> cy[i] >> cz[i] >> r[i];
    cout << asr(-8., 8., 1e-3) << endl;
}

int main() {
    cout << fixed << setprecision(3);
    while (cin >> a >> b && (a || b)) solve();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/570493.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

光速记单词-brother开头的单词

1. 思维导图 1.1 brother 1.2 mom 1.3 dad 1.4 man 2. 视频链接

13. Spring AOP(一)思想及使用

1. 什么是Spring AOP AOP的全称是Aspect Oriented Programming&#xff0c;也就是面向切面编程&#xff0c;是一种思想。它是针对OOP(面向对象编程)的一种补充&#xff0c;是对某一类事情的集中处理。比如一个博客网站的登陆验证功能&#xff0c;在用户进行新增、编辑、删除博…

js手写call、bind、apply

目录 call与applyapply bind call和apply和bind有两种实现方式&#xff0c;第一种是隐式绑定&#xff0c;第二种是通过new 无论是通过隐式绑定实现还是通过new实现&#xff0c;核心都是针对this的绑定规则 具体关于this的绑定规则可以看我这一篇博客 this绑定规则 call与apply…

【热议】硕士和读博士洗碗区别的两大理论

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验&#xff0c;帮助大家尽早适应研究生生活&#xff0c;尽快了解科研的本质。祝一切顺利&#xff01;—…

【软件测试基础】概述篇(持续更新中)

《 软件测试基础持续更新中》 这一章&#xff0c;是每一名软件测试工程师必须要掌握的常识&#xff01; 1、软件测试的目的&#xff1a;提高软件质量 和 确保软件满足用户需求。 2、软件测试的概念&#xff1a;使用人工或自动手段来运行或测试某个系统的过程&#xff0c;目的…

品牌差异化战略:Kompas.ai如何打造独特的内容声音

在当今竞争激烈的商业环境中&#xff0c;品牌差异化已成为企业获取市场优势的关键策略。一个鲜明的品牌形象和独特的内容声音不仅能够帮助企业吸引目标客户&#xff0c;还能够在消费者心中建立起独特的地位。本文将深入探讨品牌差异化的重要性&#xff0c;分析Kompas.ai如何帮助…

SL3037内置MOS管 耐压60V降压恒压芯片 降12V或降24V 电路简单

SL3037B是一款内置功率MOSFET的单片降压型开关模式转换器&#xff0c;具有以下特点&#xff1a; 1. 高效率&#xff1a;采用开关式降压技术&#xff0c;仅在需要调节输出电压时才会消耗能量&#xff0c;从而提高了整体的效率。 2. 稳定性好&#xff1a;通过精确的内部电路设计…

数睿通2.0版本升级:探索数据血缘的奥秘

引言 数睿通 2.0 迎来了 4 月份的更新&#xff0c;该版本更新了许多用户期望的数据血缘模块&#xff0c;把原来外链跳转 neo4j 页面改为自研页面&#xff0c;方便后期的二次开发完善&#xff0c;此外&#xff0c;新版本摒弃了 neo4j 的血缘数据存储方案&#xff0c;一来是因为…

接口压力测试 jmeter--进阶篇(三)

一、数据实时监控JMeterGrafanaInfluxdb &#xff08;mac&#xff09;性能监控平台搭建JMeterGrafanaInfluxdb 优点&#xff1a; 1.实时 2.美观 3.能够存储和对比 原理&#xff1a; 1.运行jmeter时会吧数据写入到influxdb 2.influxdb实时存储执行的结果 3.grafana链接.influxd…

基于 Flexbox 的纯 CSS 框架:兼容性好、文档丰富 | 开源日报 No.232

jgthms/bulma Stars: 48.3k License: MIT bulma 是基于 Flexbox 的现代 CSS 框架。 基于 Flexbox 技术。提供快速安装方式&#xff0c;支持 NPM、Yarn 和 Bower。仅包含 CSS 文件&#xff0c;没有 JavaScript 部分。兼容性良好&#xff0c;在主流浏览器上运行良好。提供丰富的…

工作中常用的5种加密算法

背景 最近&#xff0c;项目中做了一些安全性要求的整改。而加密是使用过程中常用的手段之一。这里简单的整理下&#xff0c;希望对小伙伴有帮助。 使用场景 加密是一种将原始信息&#xff08;明文&#xff09;转换成难以被直接理解的形式&#xff08;密文&#xff09;的过程…

信息收集

信息收集 域名的相关知识 域名的技术指的是一个域名由多少级组成&#xff0c;域名的各个级别被“.”分开&#xff0c;简而言之&#xff0c;有多少个点就是几级域名 顶级域名&#xff1a;.com(商)、.edu(教)、.gov(政)、.mil(军) 一级域名&#xff1a;qq.com 二级域名&#xf…

Python--容器、面向对象

一、容器类型(下) 重点学习容器的定义 常用操作的建议 跟着课堂把代码写一遍即可&#xff0c;混个脸熟&#xff0c;后面现用现查 增、删、改、查&#xff1a;重点掌握 查 字符串、元组&#xff1a;只能查&#xff0c;不能改 1.1 字符串str 1.1.1 字符串基本语法 1.1.2 字…

外呼系统出海注意事项

外呼系统在出海过程中需要注意多个方面&#xff0c;以确保系统的有效运行和合规性。以下是一些关键的注意事项&#xff1a; 一、市场调研与目标定位&#xff1a; 在出海前&#xff0c;深入调研目标市场的行业趋势、消费者偏好、文化背景和竞争态势。这有助于企业更好地了解市场…

基于麻雀搜索算法-BP神经网络SSA-BP回归预测

文章目录 效果一览文章概述订阅专栏只能获取一份代码部分源码参考资料效果一览 文章概述 基于麻雀搜索算法-BP神经网络SSA-BP回归预测 订阅专栏只能获取一份代码 部分源码 %------

几种Python处理Excel数据的方法!

第一种方法&#xff1a; 电子表格格式 我们在日常工作中常常见到各种后缀的电子表格&#xff0c;例如最常见的xlsx以及较为常见的csv、xls等格式的表格。同样是电子表格&#xff0c;它们之间有什么区别吗&#xff1f; • xls为Excel早期表格格式。 xls格式是Excel2003版本及…

TDengineGUI无法连接TDengine

可能是TDengineGUI本身的问题&#xff0c;直接下载可执行文件即可 下载地址&#xff1a;Release 1.0.3 ericyangpan/TDengineGUI (github.com) 还有可能是你的6041端口没开注意检查 可在TDengine文件夹下直接执行 systemctl start taosadapter 也可以点击 taosadapter.exe …

管理者如何在团队里讨论敏感话题

在团队中处理不便讨论的敏感话题可能会令人不适&#xff0c;但如果无视问题&#xff0c;它们会不知不觉地积聚起来&#xff0c;影响士气。 随着团队地理上越来越分散以及线上沟通增多&#xff0c;感知到团队间的不适或提出敏感话题变得更加困难。但是&#xff0c;忽略这些难以…

企业组网的作用有哪些?SD-WAN有什么优势?

在信息化的时代&#xff0c;企业组网建设逐渐成为提升企业竞争力、实现业务高效运行的关键&#xff0c;它能够为企业在信息传输、资源共享、远程办公等方面提供强大的支持。接下来&#xff0c;本文为大家详细介绍企业网络组网的意义&#xff0c;以及为大家推荐热门的网络解决方…

JVM (Micrometer)监控SpringBoot(AWS EKS版)

问题 怎样使用JVM (Micrometer)面板&#xff0c;监控Spring&#xff1f;这里不涉及Prometheus和Grafana&#xff0c;重点介绍与Micrometer与Springboot&#xff0c;k8s怎样集成。 pom.xml 引入依赖&#xff0c;如下&#xff1a; <properties><micrometer.version&…