容斥原理
来源:互联网 发布:好听的淘宝女店铺名称 编辑:程序博客网 时间:2024/06/05 10:46
引入
在1到100的数中,有多少个数是2、3、5的倍数?
这是一道小学生数学题,通常我们都是先将1到100中2、3、5的倍数的个数分别算出来,求和,然后减去6(2*3)的倍数,10(2*5)的倍数,15(3*5)的倍数的个数,最后再加上30(2*3*5)的倍数个数,就可以得到最终的答案。
其实,将上面的计算方法抽象,就可以得到逆天的容斥原理:容斥原理又称排容原理,例如在两个集的情况时,我们可以透过将 |A|和 |B|相加,再减去其交集的基数,而得到其并集的基数。
先看一下上面这张图,整张图的面积 = A + B + C - A and B - B and C - A and C + A and B and C。
容斥原理的作用主要体现在:当直接求一个值比较难求时,我们就可以用容斥原理转换成另一个易求的数值。
例题
矩形相交面积
题目描述
给出n(n <= 10)个矩形,求它们的总面积,注意会有相交部分。
这题是最基础的容斥原理(离散化更简单),几个矩形相交,做的方法有多种。
思路:
1、染色
开一个(bool)二维数组,代表整个坐标系。在输入矩形时,用双重for循环把数组中对应矩形的部分定为true,结束时用ans记录数组内true的个数即可,但这种方法太过暴力:空间O(4*10^8),时间O(4*10^9)。
2、分割(离散化)
如图,将每一个矩形分成一些小矩形,并逐一判断这些小矩形的是否在大矩形中。时间复杂度:O(N^2),空间复杂度:O(N^2)。
3、容斥原理
根据容斥原理,我们可以得到最后的ans就等于:
A的面积,B的面积,C的面积…… - A和B的重叠部分,B和C的重叠部分,A和C的重叠部分…… + A和B和C的重叠部分 …… ……
要实现枚举完这些状态,可以搜索,也可以二进制枚举。
#include <bits/stdc++.h>using namespace std;struct Map { int x1, y1; int x2, y2;}m[20], now;int a[20];bool G(int y) { //cout<<y<<endl; //printf("%d %d %d %d\n", now.x1, now.y1, now.x2, now.y2); const int weixie = false; now.x1 = max(now.x1, m[y].x1); now.y1 = min(now.y1, m[y].y1); now.x2 = min(now.x2, m[y].x2); now.y2 = max(now.y2, m[y].y2); //printf("%d %d %d %d\n", now.x1, now.y1, now.x2, now.y2); if(now.x1 > now.x2 || now.y1 < now.y2) return weixie; return true;}int Get(const int x) { if(x%2 == 0) return -1; else return 1;}bool _sort(Map x, Map y) { return (x.x1 < y.x1) || (x.x1 == y.x1 && x.y1 > y.y1);}void Change(int x) { for( int t=x, s=1; t; t/=2, s++) { a[s] = t % 2; }}int main() { freopen( "1865.in" , "r", stdin ); freopen( "1865.out", "w", stdout); int n, ans = 0; scanf("%d", &n); for( int i=1; i<=n; i++) { scanf("%d %d", &m[i].x1, &m[i].y1); scanf("%d %d", &m[i].x2, &m[i].y2); //ans += (m[i].y1 - m[i].y2) * (m[i].x2 - m[i].x1); } sort(m+1, m+n+1, _sort); for( int i=1; i<(1<<n); i++) { Change(i); int t = 0, s = 0; for( int j=1; j<=n; j++) if(a[j] == 1) { s = j; break; } for( int j=1; j<=n; j++) if(a[j] == 1) t ++; now.x1 = m[s].x1, now.x2 = m[s].x2; now.y1 = m[s].y1, now.y2 = m[s].y2; bool flag = true; for( int j=1; j<=n; j++) if(a[j] == 1) { //printf("%d %d %d %d\n", now.x1, now.y1, now.x2, now.y2); if(G(j) == false) { flag = false; break; } //printf("%d %d %d %d\n", now.x1, now.y1, now.x2, now.y2); } //printf("%d\n", flag); if(flag != false) ans += (now.y1 - now.y2) * (now.x2 - now.x1) * Get(t); } printf("%d\n", ans); return 0;}
附:
计算矩形重复面积方法如下:
bool Get(int y) { now.x1 = max(now.x1, m[y].x1); now.y1 = min(now.y1, m[y].y1); now.x2 = min(now.x2, m[y].x2); now.y2 = max(now.y2, m[y].y2); if(now.x1 > now.x2 || now.y1 < now.y2) return false; return true;}
详见下图:
阅读全文
0 0
- 容斥原理
- 容斥原理 POJ3904
- 【容斥原理】八
- 【八】容斥原理
- 广义容斥原理
- 容斥原理
- 容斥原理 专题
- 容斥原理 专题
- hdu4390 容斥原理
- hdu1695 容斥原理
- HDU3929(容斥原理)
- 整除 容斥原理
- HDU4390(容斥原理)
- 容斥原理
- poj3904 容斥原理
- 容斥原理应用
- bzoj2393 容斥原理
- hdu4135 容斥原理
- JavaSE大复习--看完就知道自己的不足
- C++ Map常见用法说明
- 关于java中文件与流的理解
- 共享内存的创建 实现卖票的程序
- 消息队列
- 容斥原理
- 初学java--重载,重写和继承
- 17.8.14号
- Python3之绑定到类的方法应用
- 数据库—内容的查询语句
- 基于Android真实项目教你一步一步搭建架构 -- 目录
- css的内联和块元素总给
- 管道方式实现文件复制
- 2. S5PV210系统时钟简介