强烈推荐此题!这个题目我做了很久,始终不得其解。后来我向dm求教,他发来代码。我对照数据才过的。
先考察一下这个问题的性质。
性质1:任何一个圆都覆盖了一个闭区域。
性质2:对于任意一个点,覆盖它的最上面的那个圆,一定是可见的。
性质3:如果一个圆不可见(它被完全覆盖),那么它的边界是被完全覆盖的。
性质4:n 个圆最多有2(n-1)
2个交点,这些交点把 n 个圆分成最多2(n-1)
2条小圆弧。
性质5:对于每个小圆弧,要么它全被覆盖,要么它全不被覆盖。
根据性质1和性质2,问题转化为恰当地找出一些点,对于每个点,把覆盖它的最上面的圆标记为可见。
根据性质3,这些点一定在所有圆的边界集合内。
根据性质5,所有小圆弧构成边界集合。每个小圆弧上只要任意取一个点就能代表整个小圆弧(边界)。不妨取中点。
至此得到算法:取所有小圆弧的中点,对每个点找到覆盖它的最上面的圆。
根据性质4,最多取2(n-1)
2个点。对每个点找到覆盖它的最上面的圆,需要O(n)次运算。总复杂度是O(n
3)。
其实此算法还有冗余,有些内部小圆弧可以不用考虑,但是我没想出怎么优化。有谁知道更好的算法,请联系我。blog留言或者qq交谈或者发邮件都可以。

 /**//*************************************************************************
/**//*************************************************************************
 Author: WHU_GCC
Author: WHU_GCC
 Created Time: 2007-8-24 12:33:03
Created Time: 2007-8-24 12:33:03
 File Name: pku1418.cpp
File Name: pku1418.cpp
 Description:
Description: 
 ************************************************************************/
************************************************************************/
 #include <iostream>
#include <iostream>
 #include <algorithm>
#include <algorithm>
 #include <vector>
#include <vector>
 #include <complex>
#include <complex>
 #include <cmath>
#include <cmath>
 using namespace std;
using namespace std;
 #define out(x) (cout << #x << ": " << x << endl)
#define out(x) (cout << #x << ": " << x << endl)
 const int maxint = 0x7FFFFFFF;
const int maxint = 0x7FFFFFFF;
 typedef long long int64;
typedef long long int64;
 const int64 maxint64 = 0x7FFFFFFFFFFFFFFFLL;
const int64 maxint64 = 0x7FFFFFFFFFFFFFFFLL;

 template <class T> void show(T a, int n)
template <class T> void show(T a, int n)  {for (int i = 0; i < n; ++i) cout << a[i] << ' '; cout << endl; }
{for (int i = 0; i < n; ++i) cout << a[i] << ' '; cout << endl; }

 template <class T> void show(T a, int r, int l)
template <class T> void show(T a, int r, int l)  {for (int i = 0; i < r; ++i) show(a[i], l); cout << endl; }
{for (int i = 0; i < r; ++i) show(a[i], l); cout << endl; }

 typedef complex <double> xy;
typedef complex <double> xy;

 const double PI = acos(-1.0);
const double PI = acos(-1.0);

 double normalize(double r)
double normalize(double r)


 {
{
 while (r < 0.0) r += 2 * PI;
    while (r < 0.0) r += 2 * PI;
 while (r >= 2 * PI) r -= 2 * PI;
    while (r >= 2 * PI) r -= 2 * PI;
 return r;
    return r;
 }
}

 int highest_cover(xy p, vector <xy> &points, vector <double> &rs)
int highest_cover(xy p, vector <xy> &points, vector <double> &rs)


 {
{
 for (int i = rs.size() - 1; i >= 0; i--)
    for (int i = rs.size() - 1; i >= 0; i--)
 if (abs(points[i] - p) < rs[i])
        if (abs(points[i] - p) < rs[i])
 return i;
            return i;
 return -1;
    return -1;
 }
}

 int main()
int main()


 {
{
 while (1)
    while (1)

 
     {
{
 int n;
        int n;
 cin >> n;
        cin >> n;
 if (!n) break;
        if (!n) break;
 vector <xy> points;
        vector <xy> points;
 vector <double> rs;
        vector <double> rs;
 for (int i = 0; i < n; i++)
        for (int i = 0; i < n; i++)

 
         {
{
 double x, y, r;
            double x, y, r;
 cin >> x >> y >> r;
            cin >> x >> y >> r;
 points.push_back(xy(x, y));
            points.push_back(xy(x, y));
 rs.push_back(r);
            rs.push_back(r);
 }
        }
 vector <bool> visible(n, false);
        vector <bool> visible(n, false);
 for (int i = 0; i < n; i++)
        for (int i = 0; i < n; i++)

 
         {
{
 vector <double> rads;
            vector <double> rads;
 rads.push_back(0.0);
            rads.push_back(0.0);
 rads.push_back(2.0 * PI);
            rads.push_back(2.0 * PI);
 for (int j = 0; j < n; j++)
            for (int j = 0; j < n; j++)

 
             {
{
 double a = rs[i];
                double a = rs[i];
 double b = abs(points[j] - points[i]);
                double b = abs(points[j] - points[i]);
 double c = rs[j];
                double c = rs[j];
 if (a + b < c || a + c < b || b + c < a) continue;
                if (a + b < c || a + c < b || b + c < a) continue;
 double d = arg(points[j] - points[i]);
                double d = arg(points[j] - points[i]);
 double e = acos((a * a + b * b - c * c) / (2 * a * b));
                double e = acos((a * a + b * b - c * c) / (2 * a * b));
 rads.push_back(normalize(d + e));
                rads.push_back(normalize(d + e));
 rads.push_back(normalize(d - e));
                rads.push_back(normalize(d - e));
 }
            }
 sort(rads.begin(), rads.end());
            sort(rads.begin(), rads.end());
 for (int j = 0; j < rads.size() - 1; j++)
            for (int j = 0; j < rads.size() - 1; j++)

 
             {
{
 double rad = (rads[j + 1] + rads[j]) / 2.0;
                double rad = (rads[j + 1] + rads[j]) / 2.0;
 double diff = 4E-13;
                double diff = 4E-13;
 for (int k = -1; k <= 1; k += 2)
                for (int k = -1; k <= 1; k += 2)

 
                 {
{
 int t = highest_cover(xy(points[i].real() + (rs[i] + diff * k) * cos(rad),
                    int t = highest_cover(xy(points[i].real() + (rs[i] + diff * k) * cos(rad),
 points[i].imag() + (rs[i] + diff * k) * sin(rad)),
                        points[i].imag() + (rs[i] + diff * k) * sin(rad)),
 points, rs);
                        points, rs);
 if (t != -1) visible[t] = true;
                    if (t != -1) visible[t] = true;
 }
                }
 }
            }
 }
        }
 int ans = 0;
        int ans = 0;
 for (int i = 0; i < n; i++)
        for (int i = 0; i < n; i++)
 if (visible[i])
            if (visible[i])
 ans++;
                ans++;
 cout << ans << endl;
        cout << ans << endl;
 }
    }
 return 0;
    return 0;
 }
}