题意:校园平面内有一些灯,在(X,Y)的点能照亮半径为R的圆的面积。两个圆有一部分重合或者边相切认为这两个圆相连。问删去一些圆是否圆1 2 3是否能直接或间接的联通。若可以则输出最大能删去的圆的数目,不行则输出-1.
原来这种神奇的东西叫做斯坦纳树。。当然最后是最短路写出来的,分别以1 2 3为源点spfa。然后求得D1【】, D2【】, D3【】。则ans = n-min(d1【】 + d2【】+d3【】)。
可能会有疑问,比如1 2 3 连接的边会有重复。不用考虑重复的部分,因为如果最小的情况存在重复的部分,那么一定会有更小的情况。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 205;
const int inf = 1 << 28;
int a[N][N];
int dis[N];
int vis[N];
int d1[N], d2[N], d3[N];
int n;
struct node{
int x, y, r;
}p[N];
int f(node a, node b)
{
if( (abs(a.x-b.x) * abs(a.x-b.x) + abs(a.y-b.y) * abs(a.y-b.y)) <= abs(a.r+b.r) * abs(a.r+b.r) )
return 1;
return inf;
}
void init()
{
for( int i = 1; i <= n; i++ )
{
for( int j = 1; j <= n; j++ )
{
a[i][j] = (i == j ? 0: inf);
}
}
}
void spfa(int st)
{
memset(vis, 0, sizeof(vis));
for( int i = 1; i <= n; i++ )
dis[i] = inf;
dis[st] = 0;
vis[st] = 1;
queue<int> q;
while( !q.empty() )
q.pop();
q.push(st);
while( !q.empty() )
{
int now = q.front();
q.pop();
vis[now] = 0;
for( int i = 1; i <= n; i++ )
{
if( !vis[i] )
{
if( dis[i] > dis[now] + a[now][i] )
{
dis[i] = dis[now] + a[now][i];
q.push(i);
vis[i] = 1;
}
}
}
}
}
int main()
{
int tot;
scanf("%d", &tot);
while(tot--)
{
scanf("%d", &n);
init();
for( int i = 1; i <= n; i++ )
scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].r);
for( int i = 1; i <= n; i++ )
{
for( int j = 1; j <= n; j++ )
{
if( i != j )
a[i][j] = f(p[i], p[j]);
}
}
spfa(1);
for( int i = 1; i <= n; i++ )
d1[i] = dis[i];
spfa(2);
for( int i = 1; i <= n; i++ )
d2[i] = dis[i];
spfa(3);
for( int i = 1; i <= n; i++ )
d3[i] = dis[i];
int ans = inf;
for( int i = 1; i <= n; i++ )
ans = min(ans, d1[i] + d2[i] + d3[i]);
if( ans == inf )
printf("-1\n");
else
printf("%d\n", n - ans - 1);
}
return 0;
}