zoukankan      html  css  js  c++  java
  • JZOJ 6489【GDOI2020模拟02.29】守卫疆域guard (最小k覆盖圆,二分+扫描线)

    Description:

    (n<=500)

    题解:

    先想一个暴力的做法。

    我们知道最小覆盖圆一定是原点集 中的三个点形成的圆或者是以原点集 中的两点为直径的圆。

    同样的道理,最小k覆盖圆肯定也满足这个性质。

    那么枚举这些圆,都判一下即可,这是(O(n^4))的。

    对于这题,可以先二分答案。

    因为圆一定至少经过一个点,所以枚举这个点x,考虑圆心绕着它旋转了一圈。

    对于每一个点y,当圆心和x的几角在一个区间时,y会在圆里。

    利用余弦定理去计算这个几角区间,然后扫描线看有没有被覆盖不少于k次的区间即可。

    复杂度:(O(n^2~log~V~log~n))

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
    #define ff(i, x, y) for(int i = x, B = y; i <  B; i ++)
    #define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    #define db double
    
    struct P {
    	db x, y;	
    	P(){}
    	P(db _x, db _y) { x = _x, y = _y;}
    };
    
    const db eps = 1e-8;
    
    P operator - (P a, P b) { return P(a.x - b.x, a.y - b.y);}
    db len(P a) { return sqrt(a.x * a.x + a.y * a.y);}
    db len2(P a) { return a.x * a.x + a.y * a.y;}
    bool operator < (P a, P b) { return a.x < b.x;}
    db ang(P a) { return atan2(a.y, a.x);}
    
    const int N = 505;
    
    const db pi = acos(-1);
    int n, k;
    P a[N], d[N * 2]; int d0;
    
    int pd(db r) {
    	if(r < 0) return 0;
    	fo(i, 1, n) {
    		d0 = 0;
    		int cnt = 1;
    		fo(j, 1, n) if(i != j) {
    			if(len2(a[j] - a[i]) < eps) {
    				cnt ++;
    			} else
    			if(len(a[j] - a[i]) <= 2 * r) {
    				db w = ang(a[j] - a[i]);
    				db t = (pi - acos((1 - len2(a[j] - a[i]) / (2 * r * r)))) / 2;
    				db l = w - t, r = w + t;
    				if(l <= r) {
    					d[++ d0] = P(l, 1);
    					d[++ d0] = P(r, -1);
    				} else {
    					cnt ++;
    					d[++ d0] = P(r, -1);
    					d[++ d0] = P(l, 1);
    				}
    			}
    		}
    		sort(d + 1, d + d0 + 1);
    		fo(j, 1, d0) {
    			cnt += (int) d[j].y;
    			if(cnt >= k) return 1;
    		}
    	}
    	return 0;
    }
    
    int main() {
    	freopen("guard.in", "r", stdin);
    	freopen("guard.out", "w", stdout);
    	scanf("%d %d", &n, &k);
    	fo(i, 1, n) scanf("%lf %lf", &a[i].x, &a[i].y);
    	db ans = 1e4;
    	for(db p = 1e4; p > 1e-5; p /= 2)
    		if(pd(ans - p)) ans -= p;
    	pp("%.10lf
    ", ans);
    }
    
  • 相关阅读:
    《挑战程序设计竞赛》 读后感
    基于SOAP的xml网络交互心得
    不用客户端,轻松下视频
    在cmd窗口中查询android的sqlite3数据库表之步骤
    单链表的插入删除以及逆转
    java中排序一个字符串数组
    求质因数
    指针与引用的区别
    统计查询-sql
    ---随心买统计查询
  • 原文地址:https://www.cnblogs.com/coldchair/p/12388629.html
Copyright © 2011-2022 走看看