zoj 1696 Viva Confetti

本文介绍了一种解决多个圆盘叠放时可见性问题的方法,通过枚举所有可能的弧并利用几何运算来确定哪些圆盘可以从特定角度观察到。讨论了如何计算弧的中点及其附近点,并通过精度调整确保计算的准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我了个去。。。写了一下午,快哭了。

这个题的精度真的是相当相当的恶心!!!
在训练指南上看到这题,思路大家应该都可以想到,枚举所有的弧,然后取弧两边的点(距离弧很近很近的),然后枚举最后是哪个盘子上的。
我的做法是取弧的中间点,然后算个从圆心到中点delta小向量,中点加减这个向量,得到两边的点。
输入是到12位精度了,因为input是10以内,为了保证精度,可以*=10000。(不乘也可以,精度得开到14~16)
其他没啥说的。
注意上面的盘子需要和所有的盘子求交点,极角排序,判断该盘子的所有弧两端所属的那个盘子是否能看到(从最上面盘子往下扫,如果点在盘子上,说明能看到这个盘子)。

弧的中点我是用中垂线算出圆的两个交点,然后叉积判断下方向,舍掉一个点。

反正挺恶心的。。

模板增加个求弧中点的函数。。。



><崩溃,刚才搜题解,发现我做过这个题!!!POJ上的。。。方法不是太一样,http://blog.youkuaiyun.com/zxy_snow/article/details/6905911,哭了,两年前做的。。哎。老了。

[cpp]  view plain copy
  1. #include <set>  
  2. #include <map>  
  3. #include <queue>  
  4. #include <stack>  
  5. #include <math.h>  
  6. #include <stdio.h>  
  7. #include <stdlib.h>  
  8. #include <iostream>  
  9. #include <limits.h>  
  10. #include <string.h>  
  11. #include <string>  
  12. #include <algorithm>  
  13. #define MID(x,y) ( ( x + y ) >> 1 )  
  14. #define L(x) ( x << 1 )  
  15. #define R(x) ( x << 1 | 1 )  
  16. #define FOR(i,s,t) for(int i=(s); i<(t); i++)  
  17. #define FORD(i,s,t) for(int i=(s-1); i>=t; i--)  
  18. #define BUG puts("here!!!")  
  19. #define STOP system("pause")  
  20. #define file_r(x) freopen(x, "r", stdin)  
  21. #define file_w(x) freopen(x, "w", stdout)  
  22.   
  23. using namespace std;  
  24.   
  25. const double eps = 1e-14;  
  26. const int MAX = 110;  
  27. const int BIG = 10000;  
  28. struct point {  
  29.     double x, y;  
  30.     point (double x=0, double y=0):x(x), y(y) {}  
  31. };  
  32. int dcmp(double x) {  
  33.     return x < -eps ? -1 : x > eps ? 1 : 0;  
  34. }  
  35. double disp2p(point a,point b) //  a b 两点之间的距离   
  36. {  
  37.     return sqrt( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) );  
  38. }  
  39. // 叉积 (三点)  
  40. double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正   
  41. {  
  42.     return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y);  
  43. }  
  44. struct circle {  
  45.     point c;  
  46.     double r;  
  47.     void big() {  
  48.         c.x *= BIG;  
  49.         c.y *= BIG;  
  50.         r *= BIG;  
  51.     }  
  52. };  
  53. bool c2c_inst(point a,double r1,point b,double r2)  
  54. {  
  55.     if( dcmp(disp2p(a,b) - (r1+r2)) < 0 && dcmp(disp2p(a,b) - fabs(r1 - r2)) > 0 )  
  56.         return true;  
  57.     return false;  
  58. }  
  59. circle c[MAX];  
  60. point l2l_inst_p(point u1,point u2,point v1,point v2)  
  61. {  
  62.     point ans = u1;  
  63.     double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/  
  64.                 ((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x));  
  65.     ans.x += (u2.x - u1.x)*t;  
  66.     ans.y += (u2.y - u1.y)*t;  
  67.     return ans;  
  68. }  
  69. void l2c_inst_p(point c,double r,point l1,point l2,point &p1,point &p2)  
  70. {  
  71.     point p = c;  
  72.     double t;  
  73.     p.x += l1.y - l2.y;  
  74.     p.y += l2.x - l1.x;  
  75.     p = l2l_inst_p(p,c,l1,l2);  
  76.     t = sqrt(r*r - disp2p(p,c)*disp2p(p,c))/disp2p(l1,l2);  
  77.     p1.x = p.x + (l2.x - l1.x)*t;  
  78.     p1.y = p.y + (l2.y - l1.y)*t;  
  79.     p2.x = p.x - (l2.x - l1.x)*t;  
  80.     p2.y = p.y - (l2.y - l1.y)*t;  
  81. }  
  82. void c2c_inst_p(point c1,double r1,point c2,double r2,point &p1,point &p2)  
  83. {  
  84.     point u,v;  
  85.     double t;  
  86.     t = (1 + (r1*r1 - r2*r2)/disp2p(c1,c2)/disp2p(c1,c2))/2;  
  87.     u.x = c1.x + (c2.x - c1.x)*t;  
  88.     u.y = c1.y + (c2.y - c1.y)*t;  
  89.     v.x = u.x + c1.y - c2.y;  
  90.     v.y = u.y - c1.x + c2.x;  
  91.     l2c_inst_p(c1,r1,u,v,p1,p2);  
  92. }  
  93. int see[MAX];  
  94. point ins[MAX], C;  
  95. bool cmp(point a,point b)    
  96. {    
  97.     double t1 = atan2(a.y - C.y, a.x - C.x);  
  98.     double t2 = atan2(b.y - C.y, b.x - C.x);  
  99.     if( dcmp(t1 - t2) == 0 ) return dcmp(fabs(a.x) - fabs(b.x)) < 0 ? true : false;  
  100.     return dcmp(t1 - t2) < 0 ? true : false;    
  101. }  
  102. int l2c_inst_p(point c,double r,point l1,point l2,point *pv)  
  103. {  
  104.     int cnt = 0;  
  105.     double d = fabs( crossProduct(c,l1,l2) )/disp2p(l1,l2);  
  106.     if( dcmp(d-r) > 0 )  
  107.         return 0;  
  108.     point p = c;  
  109.     double t;  
  110.     p.x += l1.y - l2.y;  
  111.     p.y += l2.x - l1.x;  
  112.     p = l2l_inst_p(p,c,l1,l2);  
  113.     t = sqrt(r*r - disp2p(p,c)*disp2p(p,c))/disp2p(l1,l2);  
  114.     pv[cnt].x = p.x + (l2.x - l1.x)*t;  
  115.     pv[cnt++].y = p.y + (l2.y - l1.y)*t;  
  116.     if( dcmp(d-r) == 0 )  
  117.         return cnt;  
  118.     pv[cnt].x = p.x - (l2.x - l1.x)*t;  
  119.     pv[cnt++].y = p.y - (l2.y - l1.y)*t;  
  120.     return cnt;  
  121. }  
  122. //弧ab的中点   
  123. point mid_in_arc(point a, point b, point c, double r) {  
  124.     point mid((a.x + b.x)/2, (a.y + b.y)/2);  
  125.     point p[3];  
  126.     int cnt = l2c_inst_p(c, r, mid, c, p);  
  127.     FOR(i, 0, cnt)  
  128.         if( crossProduct(c, a, p[i]) * crossProduct(c, p[i], b) && dcmp(crossProduct(c, a, p[i])) <= 0 )  
  129.             return p[i];  
  130. }  
  131. int solve(int n) {  
  132.     int ans = 0;  
  133.     memset(see, 0, sizeof(see));  
  134.     FOR(i, 0, n) {  
  135.         bool inst = false;  
  136.         int cnt = 0;  
  137.         FOR(k, i+1, n) {  
  138.             double d = disp2p(c[i].c, c[k].c);  
  139.             //被其他在它上面的圆包含了   
  140.             if( dcmp(c[k].r - d - c[i].r) >= 0 ) {  
  141.                 inst = true;  
  142.                 see[i] = -1;  
  143.                 break;  
  144.             }  
  145.             if( c2c_inst(c[i].c, c[i].r, c[k].c, c[k].r) )  
  146.                 inst = true;  
  147.         }  
  148.         //与在它上面的圆都没有相交或包含在比它之上的圆中   
  149.         if( inst == false )  
  150.             see[i] = 1;  
  151.   
  152.         FOR(k, 0, n) {  
  153.             if( k == i ) continue;  
  154.             if( !c2c_inst(c[i].c, c[i].r, c[k].c, c[k].r) )  
  155.                 continue;  
  156.             point a, b;  
  157.             c2c_inst_p(c[i].c, c[i].r, c[k].c, c[k].r, a, b);  
  158.             ins[cnt++] = a;  
  159.             ins[cnt++] = b;   
  160.         }  
  161.         C = c[i].c;  
  162.         sort(ins, ins+cnt, cmp);  
  163.         FOR(k, 0, cnt) {  
  164.             point mid = mid_in_arc(ins[k], ins[(k+1)%cnt], c[i].c, c[i].r);  
  165.             double inf = 1e12;  
  166.             point delta((c[i].c.x - mid.x)/(c[i].r*inf), (c[i].c.y - mid.y)/(c[i].r*inf));  
  167.             point p(mid.x - delta.x, mid.y - delta.y);  
  168.             for(int j=n-1; j>=0; j--) {  
  169.                 if( dcmp(disp2p(p, c[j].c) - c[j].r) < 0 ) {  
  170.                     if( see[j] == 0 ) {  
  171.                         see[j] = 1;  
  172.                     }  
  173.                     break;  
  174.                 }  
  175.             }  
  176.             p.x = mid.x + delta.x;  
  177.             p.y = mid.y + delta.y;  
  178.             bool nosee = false;  
  179.             if( see[i] == 1 )  
  180.                 continue;  
  181.             FOR(j, i+1, n) {  
  182.                 if( dcmp(disp2p(p, c[j].c) - c[j].r) < 0 ) {  
  183.                     nosee = true;  
  184.                     break;  
  185.                 }  
  186.             }  
  187.             if( !nosee )  
  188.                 see[i] = 1;  
  189.         }  
  190.     }  
  191.       
  192.     FOR(i, 0, n)  
  193.         ans += see[i] == 1 ? 1 : 0;  
  194.     return ans;  
  195. }  
  196.   
  197. int main() {  
  198.     int n;  
  199.       
  200.     while( ~scanf("%d", &n) && n ) {  
  201.         FOR(i, 0, n) {  
  202.             scanf("%lf%lf%lf", &c[i].c.x, &c[i].c.y, &c[i].r);  
  203.             c[i].big();  
  204.         }  
  205.         int ans = solve(n);  
  206.         printf("%d\n", ans);  
  207.     }  
  208.     return 0;  
  209. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值