BZOJ 1913信号覆盖

[BZOJ1913][APIO2011]信号覆盖

题解在代码后


抱怨抱怨

还是me太弱了,各种细节疏忽,把一个double数组用int comp(const int &a,const int &b)排序。导致double四舍五入为int,手动断点输出查错,查了一下午·····
还好codevs上会给错误点,不然me还查不出来这个错····
真的有毒性!!


Description

BZOJ 1913信号覆盖_第1张图片

Input

输入第一行包含一个正整数 n, 表示房子的总数。接下来有 n 行,分别表示 每一个房子的位置。对于 i = 1, 2, .., n, 第i 个房子的坐标用一对整数 xi和yi来表 示,中间用空格隔开。

Output

输出文件包含一个实数,表示平均有多少个房子被信号所覆盖,需保证输出 结果与精确值的绝对误差不超过0.01。
Sample Input
4
0 2
4 4
0 0
2 0

Sample Output
3.500

HINT

3.5, 3.50, 3.500, … 中的任何一个输出均为正确。此外,3.49, 3.51,
3.499999,…等也都是可被接受的输出。

【数据范围】

100%的数据保证,对于 i = 1, 2, .., n, 第 i 个房子的坐标(xi, yi)为整数且
–1,000,000 ≤ xi, yi ≤ 1,000,000. 任何三个房子不在同一条直线上,任何四个房子不
在同一个圆上;
40%的数据,n ≤ 100;
70%的数据,n ≤ 500;
100%的数据,3 ≤ n ≤ 1,500。


先贴个代码

BZOJ 1692ms

#include
#include
#include
#include
using namespace std;
const double Pi=3.1415926535898;
const double dPi=Pi*2;
int n;
double t[3005];
struct Point{
    int x,y;
}p[1501];
long long is_concave=0;

int comp(const double &a,const double &b){
    return along long C(int N,int M){
    long long rt=1;
    for(int i=0;i1);
    return rt;
}

void calcu(int u){
    double angle;
    for(int i=1;i<=n;i++){
        if(u==i)    {t[i]=-123456789.0;continue;}
        complex<double> poi(p[i].x-p[u].x,p[i].y-p[u].y);
        t[i]=arg(poi);
    }
}

void solve(){
    int p,dn=n*2;
    long long isnot_covered;
    for(int i=1;i<=n;i++){
        p=2;isnot_covered=0;
        calcu(i);
        sort(t+1,t+n+1,comp);
        for(int j=n+2;j<=dn;j++)
            t[j-1]=t[j-n]+dPi;
        for(int j=2;j<=n;j++){
            p=max(p,j+1);
            while(p<=dn-1&&t[p]if(p-j>=2) isnot_covered+=C(p-j,2);
        }
        is_concave+=C(n-1,3)-isnot_covered;
    }

}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&p[i].x,&p[i].y);
    solve();
    printf("%lf",3.0+((C(n,4)-is_concave)*2.0+is_concave*1.0)/C(n,3));
}

题解

很容易可以想到大暴力算法:
对于每个圆,枚举剩下的点,判断是否在圆内。

但是,会超时。
手推几组只有四个点的数据,发现一共有两种情况:
1.四个点构成凸四边形时,可以找到两个圆覆盖剩下的点
2.四个点构成凹四边形时,可以找到一个圆覆盖剩下的点

这个结论可以推广的。

这时候就可以简化问题。求出凸四边形和凹四边形的个数,答案即为
[(凸四边形数*2)+(凹四边形数*1)+(总四边形数*3)]/总四边形数。
因为三点才确定一个圆,因此总四边形数*3

考虑求解

对于一个四边形,一个顶点在另外三个顶点的构成的三角形内,我们称这个四边形是一个凸四边形。
我们需要判断一个点是否在三角形内,来确定这是个什么四边形,运用补集转化的思想,求出一个点不被三角形包含的个数,用总数去减,剩下的就是包含的。

求不包含的比较简单,但是细节多,枚举每个点作为坐标原点,对剩下的点使用极角排序

(这个就自己去查啦,me是用的complex库里自带的复数弧度角,也可以用atan2去算)

排好序后,用Θ(n)的复杂度逆时针for一遍

(想一想,过当前坐标原点作两根射线,这两根射线将平面分为两部分,其中一部分夹角<=180°。如果某个三角形三个顶点都在这个部分,那么这个三角形就不会包含当前坐标原点,正确性显然。for的过程只需要将这两根射线转一圈就好。正是为了不重不漏,我们使用极角排序,让这些点沿着顺时针有序)

算出所有不包含当前点的三角形数。再加上前面所说,这道题就写完了~

可以去看一看这一篇博客,有图好理解些。

http://blog.csdn.net/qpswwww/article/details/45334033


你可能感兴趣的:(BZOJ 1913信号覆盖)