该题题义是有一个显示器,在给定了一系列的操作后,询问最后显示器所显示的区域。
对于每个操作,给定一个x坐标和一个y坐标,以及三角形(等腰直角三角形)的边长。对于每个面积覆盖次数为奇数的区域是显示的,对于覆盖了0次或偶数次的区域是不显示的。
那么我们可以将题目这样进行转化,我们规定了个三角形的区域,它的横纵坐标分别是x, y,边长为 r 那么这个三角形可以用一个方程组来表示,令 ci = xi + yi + r,
x + y <= ci;
x >= xi;
y >= yi;
这个图形画出来就是一个三角形区域,对于后面进来的三角形,我们同样可以写出这样一个方程,我们需要解出这两个方程组的解,也就是取空间的交集。
我们得到的交集就是 x' = max(xi, xj), y' = max(yi, yj), c' = min(ci, cj); 这个重叠的区域如果有面积的话,那么也就必须满足 x' + y' < c'.
重叠的问题解决了之后,就是要解决重叠了多少次的问题了。对于这个题目,由于N(三角形的个数)最多为十个,于是我们可以直接暴力所有的组合情况,对于加了K次约束的空间,我们计算出来的结果应该是在原有的面积上乘以 2^(K-1),因为我们每次都计算了一次在没有加这个三角形的情况下的面积,同时每加上一个三角形的约束就代表着这个三角形最终被覆盖的次数加上了一,因为最后的面积一定是K个三角形的公共部分,覆盖奇数次我们就相减,偶数次我们就相加。
代码如下:
#include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> #define INF 100000000 using namespace std; typedef long long int Int64; int N, x[15], y[15], c[15]; Int64 ret; void dfs(int p, int _x, int _y, int _c, int add, int f) { if (_x + _y >= _c) { return; } if (p == N) { if (add == -1) { return; } ret += f * (1LL << add) * (_c - _x - _y) * (_c - _x - _y); return; } dfs(p+1, _x, _y, _c, add, f); dfs(p+1, max(_x, x[p+1]), max(_y, y[p+1]), min(_c, c[p+1]), add+1, -f); // 解出这个线性规划 } int main() { int r; while (scanf("%d", &N) == 1) { ret = 0; for (int i = 1; i <= N; ++i) { scanf("%d %d %d", &x[i], &y[i], &r); c[i] = x[i] + y[i] + r; } dfs(0, 0, 0, INF, -1, -1); // 初始化的条件非常宽松 printf("%I64d.%d\n", ret>>1, ret % 2? 5 : 0); // 计算三角形的时候我们并没有除以2 } return 0; }