[BZOJ 1913] signaling 信号覆盖
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1913
TIP:(注意,这题只能输出6位才能过,7位都不行wtf?)
Algorithm:
此题要从四边形的角度去考虑
对于原图中能形成的任意一个四边形:
1、如为凸四边形,明显只有对角和大于180的那两个角形成的三角形的外接圆能包含第4个点
因此每个凸四边形对答案的贡献为2
2、如为凹四边形,对答案的贡献只有1:被其他三个角形成的三角形包含的点
于是最终结果为:
$\frac{num_{凹四边形}+2num_{凸四边形}}{C_n^3(总方案数)}+3$
由于凹四边形明显比凸四边形更好求:
$\frac{num_{凹四边形}+2(C_n^4-num_{凹四边形})}{C_n^3(总方案数)}+3$
在求凹四边形时,对于每一个点,我们只要求出其被几个三角形包含即可
但反向求解明显更方便:求多少个三角形不包含x
其他点以x为原点极角排序,对于每个点计算其ANG~ANG+PI间有多少个点,再统计能生成多少个三角形
Code:
#include <bits/stdc++.h> using namespace std; typedef complex<double> point; typedef long long ll; const int MAXN=5e3; const double PI=3.1415926535897384626; int n; point dat[MAXN]; double ang[MAXN]; ll res=0; double C(double a,double b) { double ret=1; for(int i=1;i<=b;i++) ret=ret*(a-i+1)/i; return ret; } void cal(int pos) { int len=0; for(int i=1;i<=n;i++) //转为极坐标系 if(i!=pos) ang[++len]=atan2((dat[i]-dat[pos]).real(),(dat[i]-dat[pos]).imag()); sort(ang+1,ang+len+1); ll llen=len,temp=0; for(int i=1;i<=llen;i++) //首尾相接序列的基本操作 ang[++len]=ang[i]+2*PI; int cur=1; for(int i=1;i<=llen;i++) { while(cur<=len && ang[cur]<ang[i]+PI) cur++; //维护单调性 if(cur-i-1>=2) temp+=C(cur-i-1,2); } res+=C(n-1,3)-temp; } int main() { cout.setf(ios::fixed); cout.precision(6); cin >> n; for(int i=1;i<=n;i++) cin >> dat[i].real() >> dat[i].imag(); for(int i=1;i<=n;i++) cal(i); cout << (res+(C(n,4)-res)*2)/C(n,3)+3.0; return 0; }
1、求解凹四边形个数:
反向求解,利用极角排序对每个点求出不包含其的三角形的个数
2、对极坐标系的处理
由于序列是首尾相接的,要将原数组的数+2PI后扩充为原来的两倍,方便处理
3、对于包含类问题,可以将包含体和被包含点集体考虑
考虑它们看作一个整体时的性质