zoukankan      html  css  js  c++  java
  • 【bzoj2280】[Poi2011]Plot 二分+倍增+二分+最小圆覆盖

    题目描述

    给出一系列点p_1, p_2, ... , p_n,将其分成不多余m个连续的段,第i段内求一个点q_i,使得q_i到这段内点的距离的最大值的最大值最小

    输入

    第一行,n m
    下面n行,每行两个整数,表示p_i的x y坐标
    1<=m<=n<=100000
    坐标范围[-1000000,1000000] 0<p,q,r<=150,输入中至少包含一个’N’

    输出

    第一行,q_i到这段内点的距离的最大值的最大值的最小值
    第二行,分成的段数k
    下面k行,每行两个实数,表示q_k的x y坐标

    All the real numbers should be printed with at most 15 digits after the decimal point. 

    样例输入

    7 2
    2 0
    0 4
    4 4
    4 2
    8 2
    11 3
    14 2

    样例输出

    3.00000000
    2
    2.00000000 1.76393202
    11.00000000 1.99998199


    题解

    二分+倍增+二分+最小圆覆盖

    最大值最小,一眼二分答案。

    考虑怎么判定:取前任意个点跑最小圆覆盖,直到半径大于mid为止,最后看分成段的数目是否超过m即可。

    然而这样暴力跑是不行的,需要优化这个过程;同时直接再二分也是不可取的,因为二分的区间长度是满的,最坏情况下每段长度都为1,每段都需要$O(nlog n)$的时间来找,GG。

    所以需要让求最小圆覆盖的点数只与每段长有关。考虑倍增,处理出第一个$j$,满足$2^j$个不满足条件。然后在$2^{j-1}$到$2^j$之间二分处理即可。这样第一部分时间复杂度为$O(len)$,第二部分时间复杂度为$O(lenlog len)$,与n无关,所以可以满足时间要求。

    因此总的时间复杂度为$O(nlog^2n)$,然而常数巨大。。。所以才给300s。。。

    最小圆覆盖的求法参见 http://www.cnblogs.com/GXZlegend/p/7467029.html 

    CQzhangyu说卡精度,然而没看出来= = 1A了

    #include <cstdio>
    #include <algorithm>
    #define N 100010
    #define eps 1e-15
    using namespace std;
    int n , m , id[N] , tot;
    double mid , x[N] , y[N] , ansx[N] , ansy[N];
    inline double squ(double x)
    {
    	return x * x;
    }
    bool check(int lp , int rp , double &vx , double &vy)
    {
    	int i , j , k , len = rp - lp + 1;
    	double px = 0 , py = 0 , r = 0 , x1 , x2 , x3 , y1 , y2 , y3;
    	for(i = lp ; i <= rp ; i ++ ) id[i - lp + 1] = i;
    	random_shuffle(id + 1 , id + len + 1);
    	for(i = 1 ; i <= len ; i ++ )
    	{
    		if(squ(px - x[id[i]]) + squ(py - y[id[i]]) > r + eps)
    		{
    			px = x[id[i]] , py = y[id[i]] , r = 0;
    			for(j = 1 ; j < i ; j ++ )
    			{
    				if(squ(px - x[id[j]]) + squ(py - y[id[j]]) > r + eps)
    				{
    					px = (x[id[i]] + x[id[j]]) / 2 , py = (y[id[i]] + y[id[j]]) / 2 , r = (squ(x[id[i]] - x[id[j]]) + squ(y[id[i]] - y[id[j]])) / 4;
    					if(r > mid * mid + eps) return 0;
    					for(k = 1 ; k < j ; k ++ )
    					{
    						if(squ(px - x[id[k]]) + squ(py - y[id[k]]) > r + eps)
    						{
    							x1 = x[id[i]] , x2 = x[id[j]] , x3 = x[id[k]];
    							y1 = y[id[i]] , y2 = y[id[j]] , y3 = y[id[k]];
    							px = (x1 * x1 * (y2 - y3) + x2 * x2 * (y3 - y1) + x3 * x3 * (y1 - y2) - (y1 - y2) * (y2 - y3) * (y3 - y1)) / (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2;
    							py = ((x1 - x2) * (x2 - x3) * (x3 - x1) - y1 * y1 * (x2 - x3) - y2 * y2 * (x3 - x1) - y3 * y3 * (x1 - x2)) / (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2;
    							r = squ(px - x1) + squ(py - y1);
    							if(r > mid * mid + eps) return 0;
    						}
    					}
    				}
    			}
    		}
    	}
    	vx = px , vy = py;
    	return 1;
    }
    bool judge()
    {
    	int i , len , last , l , r , mid;
    	bool flag;
    	double tmpx , tmpy;
    	tot = 0;
    	for(i = 1 ; i <= n ; i = last + 1)
    	{
    		if(tot == m) return 0;
    		flag = 0;
    		for(len = 1 ; !flag ; len <<= 1)
    		{
    			if(!check(i , min(i + len - 1 , n) , tmpx , tmpy))
    			{
    				flag = 1;
    				break;
    			}
    			else if(i + len - 1 >= n)
    			{
    				tot ++ , ansx[tot] = tmpx , ansy[tot] = tmpy;
    				return 1;
    			}
    			l = i + len;
    		}
    		r = min(i + len - 1 , n) , last = l - 1;
    		while(l <= r)
    		{
    			mid = (l + r) >> 1;
    			if(check(i , mid , tmpx , tmpy)) last = mid , l = mid + 1;
    			else r = mid - 1;
    		}
    		check(i , last , tmpx , tmpy) , tot ++ , ansx[tot] = tmpx , ansy[tot] = tmpy;
    	}
    	return 1;
    }
    int main()
    {
    	srand(20011011);
    	int i , cnt = 50;
    	double l = 0 , r = 2e6;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%lf%lf" , &x[i] , &y[i]);
    	while(cnt -- )
    	{
    		mid = (l + r) / 2;
    		if(judge()) r = mid;
    		else l = mid;
    	}
    	printf("%.15lf
    " , r);
    	mid = r , judge();
    	printf("%d
    " , tot);
    	for(i = 1 ; i <= tot ; i ++ ) printf("%.15lf %.15lf
    " , ansx[i] , ansy[i]);
    	return 0;
    }
    

     

  • 相关阅读:
    记事本:js简介
    python 类的魔法函数 内置函数 类方法 静态方法 抽象类
    python 类
    python 列表 元组 字典 集合
    python:函数和循环判断
    记事本:盒模型
    第5章学习小结
    倍增法求LCA(最近公共最先)
    L
    第4章学习小结
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7467099.html
Copyright © 2011-2022 走看看