LA2572 UVA1308

来源:互联网 发布:社交网络肖恩帕克最后 编辑:程序博客网 时间:2024/05/21 22:36

Do you know confetti? They are small discs of colored paper, and people throw them around during parties or festivals. Since people throw lots of confetti, they may end up stacked one on another, so there may be hidden ones underneath.

A handful of various sized confetti have been dropped on a table. Given their positions and sizes, can you tell us how many of them you can see?

The following figure represents the disc configuration for the first sample input, where the bottom disc is still visible.

\epsfbox{p2572.eps}

Input 

The input is composed of a number of configurations of the following form.


n  x1y1r1x2y2r2$ \vdots$  xnynrn


The first line in a configuration is the number of discs in the configuration (a positive integer not more than 100), followed by one Ine descriptions of each disc: coordinates of its center and radius, expressed as real numbers in decimal notation, with up to 12 digits after the decimal point. The imprecision margin is $ \pm$5x 10-13 . That is, it is guaranteed that variations of less than$ \pm$5x 10-13 on input values do not change which discs are visible. Coordinates of all points contained in discs are between -10 and 10.

Confetti are listed in their stacking order, x1y1 r1 being the bottom one andxn ynrn the top one. You are observing from the top.

The end of the input is marked by a zero on a single line.

Output 

For each configuration you should output the number of visible confetti on a single line.

Sample Input 

30 0 0.5-0.9 0 1.000000000010.9 0 1.0000000000150 1 0.51 1 1.000000000010 2 1.00000000001-1 1 1.000000000010 -0.00001 1.0000000000150 1 0.51 1 1.000000000010 2 1.00000000001-1 1 1.000000000010 0 1.0000000000120 0 1.00000010 0 120 0 10.00000001 0 10

Sample Output 

3542

2

// LA2572/UVa1308 Viva Confetti// Rujia Liu#include<cmath>#include<algorithm>#include<cstring>#include<iostream>#include<vector>using namespace std;const double eps = 5 * 1e-13;int dcmp(double x) {  if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;}const double PI = acos(-1);const double TWO_PI = PI * 2;double NormalizeAngle(double rad, double center = PI) {  return rad - TWO_PI * floor((rad + PI - center) / TWO_PI);}struct Point {  double x, y;  Point(double x=0, double y=0):x(x),y(y) { }};typedef Point Vector;Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y-B.y); }Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p); }double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }double Length(Vector A) { return sqrt(Dot(A, A)); }double angle(Vector v) {  return atan2(v.y, v.x);}// 交点相对于圆1的极角保存在rad中void getCircleCircleIntersection(Point c1, double r1, Point c2, double r2, vector<double>& rad) {  double d = Length(c1 - c2);  if(dcmp(d) == 0) return; // 不管是内含还是重合,都不相交  if(dcmp(r1 + r2 - d) < 0) return;  if(dcmp(fabs(r1-r2) - d) > 0) return;  double a = angle(c2 - c1);  double da = acos((r1*r1 + d*d - r2*r2) / (2*r1*d));  rad.push_back(NormalizeAngle(a-da));  rad.push_back(NormalizeAngle(a+da));}const int maxn = 100 + 5;int n;Point center[maxn];double radius[maxn];bool vis[maxn];// 覆盖点p的最上层的圆int topmost(Point p) {  for(int i = n-1; i >= 0; i--)//自顶向底 枚举每个圆看能不能覆盖这个点!    if(Length(center[i]-p) < radius[i]) return i;  return -1;}int main() {  while(cin >> n) {    if(!n) break;    for(int i = 0; i < n; i++) {      double x, y, r;      cin >> x >> y >> r;      center[i] = Point(x, y);      radius[i] = r;    }    memset(vis, 0, sizeof(vis));    for(int i = 0; i < n; i++) { // 自底向上 枚举每个圆。      // 考虑圆i被切割成的各个圆弧。把圆周当做区间来处理,起点是0,终点是2PI      vector<double> rad;      rad.push_back(0);      rad.push_back(PI*2);/**对于那些和其他圆没有交点的圆,那么这段小圆弧就是整个圆周**/      for(int j = 0; j < n; j++)        getCircleCircleIntersection(center[i], radius[i], center[j], radius[j], rad);//求出每个圆与 该圆i 的交点。      sort(rad.begin(), rad.end());//按极角排序      for(int j = 0; j < rad.size(); j++) { //枚举每个小圆弧        double mid = (rad[j] + rad[j+1]) / 2.0; // 圆弧中点相对于圆i圆心的极角        for(int side = -1; side <= 1; side += 2) {          double r2 = radius[i] - side*eps; // 往里面或者外面稍微一动一点点          int t = topmost(Point(center[i].x + cos(mid)*r2, center[i].y + sin(mid)*r2));//看这个稍稍移动的点 在哪个圆上。          if(t >= 0) vis[t] = true;//标记这个点在的小圆弧为真。        }      }    }    int ans = 0;    for(int i = 0; i < n; i++) if(vis[i]) ans++;    cout << ans << "\n";  }  return 0;}



0 0
原创粉丝点击