大意:给定一些灯泡,灯泡的照明范围是R,当两个圆相切或者相交时可以看做一个连通的,问最多可以去掉多少个灯泡使得剩下的3个圆还是连通的。

思路:把圆看做顶点,判断圆是否相交,如果相交,赋边权为1,然后枚举一个定点到三个点的最小值,用总数减去最小值减1即是答案。

 

View Code
/*最短路;三点连通*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 210;
const int maxm = 1000*1000;

typedef int LL;

struct Edge
{
    LL v;
    LL w;
    LL next;
}edge[maxm];

LL cnt;

LL n, m;

LL first[maxn];
LL d1[maxn], d2[maxn], d3[maxn];

void read_graph(LL u, LL v, LL w)
{
    edge[cnt].v = v, edge[cnt].w = w;
    edge[cnt].next = first[u], first[u] = cnt++;
}

void spfa(int src, int *d)
{
    queue<int> q;
    bool inq[maxn] = {0};
    for(int i = 1; i <= n; i++) d[i] = (i == src)?0:INF;
    q.push(src);
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        inq[x] = 0;
        for(int e = first[x]; e != -1; e = edge[e].next)
        {
            int v = edge[e].v, w = edge[e].w;
            if(d[v] > d[x] + w)
            {
                d[v] = d[x] + w;
                if(!inq[v])
                {
                    inq[v] = 1;
                    q.push(v);
                }
            }
        }
    }
}

void init()
{
    cnt = 0;
    memset(first, -1, sizeof(first));
}

struct Point
{
    double x, y;
    double R;
}A[maxn];

const double eps = 1e-8;

double sqr(double x) { return x*x; }
double Dist(Point a, Point b) { return sqrt(sqr(a.x-b.x) + sqr(a.y-b.y)); }

int dcmp(double x) { if(fabs(x) < eps) return 0; else return x < 0? -1 : 1; }

void read_case()
{
    init();
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%lf%lf%lf", &A[i].x, &A[i].y, &A[i].R);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++) if(i != j)
        {
            double t = Dist(A[i], A[j]);
            if(dcmp(t-A[i].R-A[j].R) <= 0) read_graph(i, j, 1), read_graph(j, i, 1);
        }
    }
}

void solve()
{
    read_case();
    spfa(1, d1); spfa(2, d2); spfa(3, d3);
    int ans = INF;
    for(int i = 1; i <= n; i++)
    {
        if(d1[i] != INF && d2[i] != INF && d3[i] != INF)
            ans = min(ans, d1[i]+d2[i]+d3[i]);
    }
    if(ans < INF) printf("%d\n", n-ans-1);
    else printf("-1\n");
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        solve();
    }
    return 0;
}

 

 

 

posted on 2013-04-28 16:44  Buck Meister  阅读(121)  评论(0编辑  收藏  举报