uvalive 7675 | 2016 北京 regional onsite H - A New Ground Heating Device (二分+多个圆面积并)

题目链接

题意:

在一个二维平面上,有n个加热设备,每个加热设备加热一个圆形,加热设备需要信号源才可以工作,信号源在原点上,但是高度不确定。假设设备的加热半径是一个与{信号源与设备的距离}有关的表达式。现在想要满足,至少有k个加热设备加热的面积大于s,问信号源的最高高度是多少。

思路:

训练的时候一眼二分,但是求圆并的时候gg了。。毫无思路。

搞定了多个圆面积并。。这题就很easy了。。

需要注意,每次二分的时候,记得初始化圆的d…

  1/* ***********************************************
  2Author :111qqz
  3File Name :H.cpp
  4************************************************ */
  5
  6#include <cstdio>
  7#include <cstring>
  8#include <iostream>
  9#include <algorithm>
 10#include <vector>
 11#include <queue>
 12#include <set>
 13#include <map>
 14#include <string>
 15#include <cmath>
 16#include <cstdlib>
 17#include <ctime>
 18#define PB push_back
 19#define fst first
 20#define sec second
 21#define lson l,m,rt<<1
 22#define rson m+1,r,rt<<1|1
 23#define ms(a,x) memset(a,x,sizeof(a))
 24#define pi pair < int ,int >
 25#define MP make_pair
 26using namespace std;
 27typedef long long LL;  
 28typedef unsigned long long ULL;  
 29typedef vector <int> VI;  
 30const int INF = 0x3f3f3f3f;  
 31const double eps = 1e-6;  
 32const int MAXN = 1E3+7;  
 33const double PI = acos(-1.0);  
 34#define sqr(x) ((x)*(x))  
 35const int N = 1010;  
 36double area[N];  
 37int n,k;
 38double Z[N];
 39double W,S;
 40
 41
 42int dblcmp(double d){ return d<-eps?-1:d>eps;}  
 43struct point
 44{
 45    double x,y;
 46    double ang;
 47    int d;
 48    point(){}
 49    point(double x,double y):x(x),y(y){}
 50    point(double _x,double _y,double _ang,int _d)
 51    {
 52    x = _x;
 53    y = _y;
 54    ang = _ang;
 55    d = _d;
 56    }
 57    void input(){scanf("%lf%lf",&x,&y);}
 58    double angle(){ return atan2(y,x);}
 59    point operator + (const point &rhs)const{ return point(x+rhs.x,y+rhs.y);}
 60    point operator - (const point &rhs)const{ return point(x-rhs.x,y-rhs.y);}
 61    point operator * (double t)const{ return point(t*x,t*y);}
 62    point operator / (double t)const{ return point(x/t,y/t);}
 63    double length() const { return sqrt(x*x+y*y);};
 64    double length2() const { return x*x + y*y;}
 65    point unit()const { double l = length();return point(x/l,y/l); }
 66}tp[N*2];
 67double cross (const point a,point b){ return a.x*b.y-a.y*b.x ;}
 68double dist(const point p1,point p2) { return (p1-p2).length();}
 69struct circle  
 70{ 
 71    point c;
 72    double r;
 73    double Z;
 74    int d; 
 75    void pr()
 76    {
 77    printf(" (%.3f,%.3f) r=%.3f\n",c.x,c.y,r);
 78    }
 79    void input()  
 80    {  
 81    c.input();
 82    scanf("%lf",&r);
 83        d = 1;  
 84    }
 85    bool contain (const circle & cir)const{ return dblcmp(dist(cir.c,c)+cir.r-r)<=0;}
 86    bool interect (const circle & cir)const{ return dblcmp(dist(cir.c,c)-cir.r-r)<0;}
 87} cir[N];// tp[N * 2];  
 88
 89double dis(point a, point b)  {return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));} 
 90int CirCrossCir(circle cir1,circle cir2, point &p1, point &p2)  
 91{  
 92    point m = cir2.c-cir1.c;
 93    point s = cir2.c+cir1.c;
 94    point m2 = point(sqr(m.x),sqr(m.y));
 95    double dis2 = m2.x + m2.y, d = -(dis2 - sqr(cir1.r - cir2.r)) * (dis2 - sqr(cir1.r + cir2.r));  
 96    if (d + eps < 0) return 0;  
 97    if (d < eps) d = 0;  
 98    else d = sqrt(d);
 99    double x = m.x * ((cir1.r + cir2.r) * (cir1.r - cir2.r) + m.x * s.x) + s.x * m2.y;  
100    double y = m.y * ((cir1.r+ cir2.r) * (cir1.r - cir2.r) + m.y * s.y) + s.y * m2.x;  
101    point dp = m*d;
102    dis2 *= 2;
103    p1 = point (x-dp.y,y+dp.x)/dis2;
104    p2 = point (x+dp.y,y-dp.x)/dis2;
105    if (d > eps) return 2;  
106    else return 1;  
107}  
108bool circmp(const circle& u, const circle& v)  
109{  
110    return dblcmp(u.r - v.r) < 0;  
111}  
112bool cmp(const point& u, const point& v)  
113{  
114    if (dblcmp(u.ang - v.ang)) return u.ang < v.ang;  
115    return u.d > v.d;  
116}  
117
118double calc(circle cir, point p1, point p2)  
119{  
120    double ans = (p2.ang - p1.ang) * sqr(cir.r)
121         - cross ( (p1-cir.c),(p2-cir.c)) + cross( p1,p2);
122    return ans *0.5; 
123}  
124void CirUnion(circle cir[], int n)  
125{  
126    circle cir1, cir2;  
127    point p1,p2;
128    sort(cir, cir + n, circmp);  
129    for (int i = 0; i < n; ++i)  
130        for (int j = i + 1; j < n; ++j)  
131        if (cir[j].contain(cir[i]))
132                cir[i].d++;  
133    for (int i = 0; i < n; ++i)  
134    {  
135        int tn = 0, cnt = 0;  
136        for (int j = 0; j < n; ++j)  
137        {  
138            if (i == j) continue;  
139            if (CirCrossCir(cir[i],cir[j],p2, p1) < 2) continue;  
140        p1.ang = (p1-cir[i].c).angle();
141        p2.ang = (p2-cir[i].c).angle();
142            p1.d = 1;  
143            tp[tn++] = p1;  
144            p2.d = -1;  
145            tp[tn++] = p2;  
146            if (dblcmp(p1.ang - p2.ang) > 0) cnt++;  
147        }  
148        tp[tn++] = point(cir[i].c.x - cir[i].r, cir[i].c.y, PI, -cnt);  
149        tp[tn++] = point(cir[i].c.x - cir[i].r, cir[i].c.y, -PI, cnt);  
150        sort(tp, tp + tn, cmp);  
151        int p, s = cir[i].d + tp[0].d;  
152        for (int j = 1; j < tn; ++j)  
153        {  
154            p = s;  
155            s += tp[j].d;  
156            area[p] += calc(cir[i], tp[j - 1], tp[j]);  
157        }  
158    }  
159}  
160bool check( double h)  
161{ 
162   // cout<<"h:"<<h<<"  ";
163
164    for ( int i = 0 ; i < n ; i++)
165    {
166    double l = sqrt(cir[i].c.length2() + h*h);
167    double r = W/(l*cir[i].Z);
168    cir[i].r = r;
169    cir[i].d = 1; //多次,是累加值,记得每次二分都要初始化。
170    //cir[i].pr();
171    }
172
173    memset(area, 0, sizeof(area));
174    ms(tp,0);
175    CirUnion(cir, n);  
176    //去掉重复计算的  
177    for (int i = 1; i <= n; ++i)  
178    {  
179        area[i] -= area[i + 1];  
180    }  
181    //area[i]为重叠了i次的面积 
182    double sum=0;
183    for ( int i = k ; i <= n ; i++) sum = sum + area[i];
184    //sum = fabs(sum);
185    return dblcmp(sum-S)>0;
186    //tot 为总面积  
187    //double tot = 0;  
188    //for(int i=1; i<=n; i++) tot += area[i];  
189    //printf("%f\n", tot);  
190}  
191
192bool ok;
193double bin()
194{
195    double l = 0;
196    double r = 10000;
197    while (dblcmp(l-r)<0)
198    {
199    double mid = (l+r)*0.5;
200    //printf("l: %.4f r:%.4f mid:%.4f \n",l,r,mid); 
201    if (check(mid)) l = mid,ok = true;
202    else r = mid;
203    }
204    return l;
205}
206int main()  
207{  
208   // freopen("./in.txt", "r", stdin);
209    int T;
210    cin>>T;
211    while (T--)
212    {
213    ok = false;
214    cin>>n>>W>>k>>S;
215    for ( int i = 0 ; i < n ; i++) 
216    {
217        cir[i].c.input();
218        scanf("%lf",&cir[i].Z);
219    }
220    double ans =bin();
221    if (!ok) puts("No solution!");
222    else
223    {
224        if (dblcmp(ans-500)>0) puts("Oops!");
225        else printf("%.4f\n",ans);
226    }
227    }
228
229
230
231
232    return 0;  
233}