hdu 3832 Earth Hour(斯坦纳树)

题意:校园平面内有一些灯,在(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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值