我了个去。。。写了一下午,快哭了。
这个题的精度真的是相当相当的恶心!!!
在训练指南上看到这题,思路大家应该都可以想到,枚举所有的弧,然后取弧两边的点(距离弧很近很近的),然后枚举最后是哪个盘子上的。
我的做法是取弧的中间点,然后算个从圆心到中点delta小向量,中点加减这个向量,得到两边的点。
输入是到12位精度了,因为input是10以内,为了保证精度,可以*=10000。(不乘也可以,精度得开到14~16)
其他没啥说的。
注意上面的盘子需要和所有的盘子求交点,极角排序,判断该盘子的所有弧两端所属的那个盘子是否能看到(从最上面盘子往下扫,如果点在盘子上,说明能看到这个盘子)。
弧的中点我是用中垂线算出圆的两个交点,然后叉积判断下方向,舍掉一个点。
反正挺恶心的。。
模板增加个求弧中点的函数。。。
><崩溃,刚才搜题解,发现我做过这个题!!!POJ上的。。。方法不是太一样,http://blog.youkuaiyun.com/zxy_snow/article/details/6905911,哭了,两年前做的。。哎。老了。
- #include <set>
- #include <map>
- #include <queue>
- #include <stack>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <iostream>
- #include <limits.h>
- #include <string.h>
- #include <string>
- #include <algorithm>
- #define MID(x,y) ( ( x + y ) >> 1 )
- #define L(x) ( x << 1 )
- #define R(x) ( x << 1 | 1 )
- #define FOR(i,s,t) for(int i=(s); i<(t); i++)
- #define FORD(i,s,t) for(int i=(s-1); i>=t; i--)
- #define BUG puts("here!!!")
- #define STOP system("pause")
- #define file_r(x) freopen(x, "r", stdin)
- #define file_w(x) freopen(x, "w", stdout)
- using namespace std;
- const double eps = 1e-14;
- const int MAX = 110;
- const int BIG = 10000;
- struct point {
- double x, y;
- point (double x=0, double y=0):x(x), y(y) {}
- };
- int dcmp(double x) {
- return x < -eps ? -1 : x > eps ? 1 : 0;
- }
- double disp2p(point a,point b) // a b 两点之间的距离
- {
- return sqrt( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) );
- }
- // 叉积 (三点)
- double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正
- {
- return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);
- }
- struct circle {
- point c;
- double r;
- void big() {
- c.x *= BIG;
- c.y *= BIG;
- r *= BIG;
- }
- };
- bool c2c_inst(point a,double r1,point b,double r2)
- {
- if( dcmp(disp2p(a,b) - (r1+r2)) < 0 && dcmp(disp2p(a,b) - fabs(r1 - r2)) > 0 )
- return true;
- return false;
- }
- circle c[MAX];
- point l2l_inst_p(point u1,point u2,point v1,point v2)
- {
- point ans = u1;
- double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/
- ((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x));
- ans.x += (u2.x - u1.x)*t;
- ans.y += (u2.y - u1.y)*t;
- return ans;
- }
- void l2c_inst_p(point c,double r,point l1,point l2,point &p1,point &p2)
- {
- point p = c;
- double t;
- p.x += l1.y - l2.y;
- p.y += l2.x - l1.x;
- p = l2l_inst_p(p,c,l1,l2);
- t = sqrt(r*r - disp2p(p,c)*disp2p(p,c))/disp2p(l1,l2);
- p1.x = p.x + (l2.x - l1.x)*t;
- p1.y = p.y + (l2.y - l1.y)*t;
- p2.x = p.x - (l2.x - l1.x)*t;
- p2.y = p.y - (l2.y - l1.y)*t;
- }
- void c2c_inst_p(point c1,double r1,point c2,double r2,point &p1,point &p2)
- {
- point u,v;
- double t;
- t = (1 + (r1*r1 - r2*r2)/disp2p(c1,c2)/disp2p(c1,c2))/2;
- u.x = c1.x + (c2.x - c1.x)*t;
- u.y = c1.y + (c2.y - c1.y)*t;
- v.x = u.x + c1.y - c2.y;
- v.y = u.y - c1.x + c2.x;
- l2c_inst_p(c1,r1,u,v,p1,p2);
- }
- int see[MAX];
- point ins[MAX], C;
- bool cmp(point a,point b)
- {
- double t1 = atan2(a.y - C.y, a.x - C.x);
- double t2 = atan2(b.y - C.y, b.x - C.x);
- if( dcmp(t1 - t2) == 0 ) return dcmp(fabs(a.x) - fabs(b.x)) < 0 ? true : false;
- return dcmp(t1 - t2) < 0 ? true : false;
- }
- int l2c_inst_p(point c,double r,point l1,point l2,point *pv)
- {
- int cnt = 0;
- double d = fabs( crossProduct(c,l1,l2) )/disp2p(l1,l2);
- if( dcmp(d-r) > 0 )
- return 0;
- point p = c;
- double t;
- p.x += l1.y - l2.y;
- p.y += l2.x - l1.x;
- p = l2l_inst_p(p,c,l1,l2);
- t = sqrt(r*r - disp2p(p,c)*disp2p(p,c))/disp2p(l1,l2);
- pv[cnt].x = p.x + (l2.x - l1.x)*t;
- pv[cnt++].y = p.y + (l2.y - l1.y)*t;
- if( dcmp(d-r) == 0 )
- return cnt;
- pv[cnt].x = p.x - (l2.x - l1.x)*t;
- pv[cnt++].y = p.y - (l2.y - l1.y)*t;
- return cnt;
- }
- //弧ab的中点
- point mid_in_arc(point a, point b, point c, double r) {
- point mid((a.x + b.x)/2, (a.y + b.y)/2);
- point p[3];
- int cnt = l2c_inst_p(c, r, mid, c, p);
- FOR(i, 0, cnt)
- if( crossProduct(c, a, p[i]) * crossProduct(c, p[i], b) && dcmp(crossProduct(c, a, p[i])) <= 0 )
- return p[i];
- }
- int solve(int n) {
- int ans = 0;
- memset(see, 0, sizeof(see));
- FOR(i, 0, n) {
- bool inst = false;
- int cnt = 0;
- FOR(k, i+1, n) {
- double d = disp2p(c[i].c, c[k].c);
- //被其他在它上面的圆包含了
- if( dcmp(c[k].r - d - c[i].r) >= 0 ) {
- inst = true;
- see[i] = -1;
- break;
- }
- if( c2c_inst(c[i].c, c[i].r, c[k].c, c[k].r) )
- inst = true;
- }
- //与在它上面的圆都没有相交或包含在比它之上的圆中
- if( inst == false )
- see[i] = 1;
- FOR(k, 0, n) {
- if( k == i ) continue;
- if( !c2c_inst(c[i].c, c[i].r, c[k].c, c[k].r) )
- continue;
- point a, b;
- c2c_inst_p(c[i].c, c[i].r, c[k].c, c[k].r, a, b);
- ins[cnt++] = a;
- ins[cnt++] = b;
- }
- C = c[i].c;
- sort(ins, ins+cnt, cmp);
- FOR(k, 0, cnt) {
- point mid = mid_in_arc(ins[k], ins[(k+1)%cnt], c[i].c, c[i].r);
- double inf = 1e12;
- point delta((c[i].c.x - mid.x)/(c[i].r*inf), (c[i].c.y - mid.y)/(c[i].r*inf));
- point p(mid.x - delta.x, mid.y - delta.y);
- for(int j=n-1; j>=0; j--) {
- if( dcmp(disp2p(p, c[j].c) - c[j].r) < 0 ) {
- if( see[j] == 0 ) {
- see[j] = 1;
- }
- break;
- }
- }
- p.x = mid.x + delta.x;
- p.y = mid.y + delta.y;
- bool nosee = false;
- if( see[i] == 1 )
- continue;
- FOR(j, i+1, n) {
- if( dcmp(disp2p(p, c[j].c) - c[j].r) < 0 ) {
- nosee = true;
- break;
- }
- }
- if( !nosee )
- see[i] = 1;
- }
- }
- FOR(i, 0, n)
- ans += see[i] == 1 ? 1 : 0;
- return ans;
- }
- int main() {
- int n;
- while( ~scanf("%d", &n) && n ) {
- FOR(i, 0, n) {
- scanf("%lf%lf%lf", &c[i].c.x, &c[i].c.y, &c[i].r);
- c[i].big();
- }
- int ans = solve(n);
- printf("%d\n", ans);
- }
- return 0;
- }