zoukankan      html  css  js  c++  java
  • 【Luogu P4406】「CQOI2005」三角形面积并

    Description

    给出 (n) 个三角形,求这 (n) 个三角形并的面积。

    数据范围:(1 leq n leq 100)(-10^6 leq x, y leq 10^6)

    Solution

    扫描线的做法大家都会,这篇题解的做法是自适应辛普森积分。

    (f(t)) 表示:给出的 (n) 个三角形与直线 (x = t) 的交集长度。

    那么答案即为:

    [int_a^b f(x) ext{dx} ]

    其中 (a, b) 分别表示输入的 (x) 中的最小值和最大值。

    那么可以使用自适应辛普森积分做。现在的关键是要如何求出任意一个 (f(t))
    对于每一个三角形,考虑求出这个三角形与直线 (x = t) 的相交部分是哪一段区间,把这些区间提出来,区间合并即可求出函数值。计算一个函数值的时间复杂度是 (mathcal{O}(n log n)) 的,可以接受。

    然后需要提高精度:

    • 可以在递归过程中设置一个强制执行的最少迭代层数。
    • 可以将每个三角形的最小 (x) 值和最大 (x) 值提出来后排序,对所有相邻点构成的区间求积分,将这些积分相加,就可以得到最后大区间 ([a, b]) 的积分。

    Code

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    
    using namespace std;
    
    const double eps = 1e-9;
    const double INF = 1e6;
    
    int sgn(double n) {
    	if (fabs(n) < eps) return 0;
    	return n > 0 ? 1 : -1; 
    }
    
    int dcmp(double x, double y) {
    	return sgn(x - y);
    }
    
    struct point {
    	double x, y;
    
    	point() { x = y = 0; }
    	point(double A, double B) : x(A), y(B) {}
    };
    
    typedef point vec;
    
    vec operator + (vec a, vec b) { return vec(a.x + b.x, a.y + b.y); }
    vec operator - (vec a, vec b) { return vec(a.x - b.x, a.y - b.y); }
    vec operator * (vec a, double b) { return vec(a.x * b, a.y * b); }
    vec operator / (vec a, double b) { return vec(a.x / b, a.y / b); }
    
    bool operator < (point a, point b) {
    	if (dcmp(a.x, b.x)) return a.x < b.x;
    	return a.y < b.y;
    }
    
    double cross(vec a, vec b) {
    	return a.x * b.y - a.y * b.x;
    }
    
    point line_intersection(point A, point B, point C, point D) {
    	point p = A, q = C;
    	vec x = B - A, y = D - C;
    
    	vec u = q - p;
    	double t = cross(u, y) / cross(x, y);
    	return p + x * t;
    }
    
    const int N = 110;
    
    int n;
    vector<point> a[N];
    
    int t;
    double pos[N * 2];
    
    int m;
    struct range {
    	double l, r;
    
    	range() {}
    	range(double A, double B) : l(A), r(B) {}
    } b[N];
    
    bool ruler(range a, range b) {
    	if (dcmp(a.l, b.l)) return a.l < b.l;
    	return a.r < b.r;
    }
    
    double f(double x) {
    	point Ga = point(x, 0), Gb = point(x, 1);
    
    	m = 0;
    	for (int i = 1; i <= n; i ++) {
    		vector<point> u = a[i];
    
    		if (dcmp(x, u[0].x) < 0) continue;
    		if (dcmp(x, u[2].x) > 0) continue;
    
    		if (!dcmp(u[0].x, u[1].x) && !dcmp(u[0].x, x)) {
    			b[++ m] = range(u[0].y, u[1].y);
    		} else if (!dcmp(u[1].x, u[2].x) && !dcmp(u[1].x, x)) {
    			b[++ m] = range(u[1].y, u[2].y);
    		} else {
    			vector<double> seq;
    			seq.clear();
    
    			for (int j = 0; j < 3; j ++) {
    				point A = u[j], B = u[(j + 1) % 3];
    				if (B < A) swap(A, B);
    
    				if (dcmp(x, A.x) < 0) continue;
    				if (dcmp(x, B.x) > 0) continue;
    
    				seq.push_back(line_intersection(A, B, Ga, Gb).y);
    			}
    
    			sort(seq.begin(), seq.end());
    			b[++ m] = range(seq[0], seq[seq.size() - 1]);
    		}
    	}
    
    	if (!m) return 0;
    
    	sort(b + 1, b + 1 + m, ruler);
    
    	double ans = 0;
    	double st = b[1].l, ed = b[1].r;
    
    	for (int i = 2; i <= m; i ++) {
    		if (dcmp(b[i].l, ed) > 0)
    			ans += ed - st,
    			st = b[i].l, ed = b[i].r;
    		else
    			ed = max(ed, b[i].r);
    	}
    
    	ans += ed - st;
    
    	return ans;
    }
    
    double simpson(double Lv, double Mv, double Rv, double len) {
    	return (Lv + Rv + 4 * Mv) * len / 6; 
    }
    
    double asr(double l, double r, double Lv, double Mv, double Rv, int dep) {
    	double mid = (l + r) / 2;
    	double A = f((l + mid) / 2), B = f((mid + r) / 2);
    
    	double s = simpson(Lv, Mv, Rv, r - l);
    	double Ls = simpson(Lv, A, Mv, mid - l);
    	double Rs = simpson(Mv, B, Rv, r - mid);
    
    	if (!dcmp(s, Ls + Rs) && dep <= 0) return Ls + Rs;
    	return asr(l, mid, Lv, A, Mv, dep - 1) + asr(mid, r, Mv, B, Rv, dep - 1);
    }
    
    int main() {
    	scanf("%d", &n);
    
    	for (int i = 1; i <= n; i ++) {
    		for (int j = 0; j < 3; j ++) {
    			double x, y;
    			scanf("%lf%lf", &x, &y);
    
    			a[i].push_back(point(x, y));
    		}
    
    		sort(a[i].begin(), a[i].end());
    
    		pos[++ t] = a[i][0].x;
    		pos[++ t] = a[i][2].x;
    	}
    
    	sort(pos + 1, pos + 1 + t);
    
    	double ans = 0;
    
    	for (int i = 2; i <= t; i ++) {
    		if (!dcmp(pos[i - 1], pos[i])) continue;
    
    		double l = pos[i - 1], r = pos[i];
    		ans += asr(l, r, f(l), f((l + r) / 2), f(r), 5);
    	}
    
    	printf("%.2lf
    ", ans);
    
    	return 0;
    }
    
    keep the love forever.
  • 相关阅读:
    NOP源码分析六--实体、数据的分层与处理。
    NOP源码分析七---继续
    NOP源码分析 八---set的存储
    Nop 源码分析四 任务系统
    NOP源码分析五,文件位置等详细内容,感冒真难受,嗓子痒又疼。。
    1
    mobx
    ts随笔
    13.vue-vuex
    13.vue-axios
  • 原文地址:https://www.cnblogs.com/cjtcalc/p/15187206.html
Copyright © 2011-2022 走看看