hdu5934(强连通+缩点)

本文深入探讨了一种复杂问题:如何利用最小成本引爆一系列具有特定属性的炸弹。通过引入强连通组件的概念,文章详细解析了算法设计与实现过程,包括输入输出格式、代码实现细节及样例解释,旨在帮助读者掌握强连通组件在解决此类问题中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

There are NN bombs needing exploding.

Each bomb has three attributes: exploding radius riri, position (xi,yi)(xi,yi) and lighting-cost cici which means you need to pay cici cost making it explode.

If a un-lighting bomb is in or on the border the exploding area of another exploding one, the un-lighting bomb also will explode.

Now you know the attributes of all bombs, please use the minimum cost to explode all bombs.
Input
First line contains an integer TT, which indicates the number of test cases.

Every test case begins with an integers NN, which indicates the numbers of bombs.

In the following NN lines, the ith line contains four intergers xixi, yiyi, riri and cici, indicating the coordinate of ith bomb is (xi,yi)(xi,yi), exploding radius is riri and lighting-cost is cici.

Limits

  • 1≤T≤201≤T≤20
  • 1≤N≤10001≤N≤1000
  • −108≤xi,yi,ri≤108−108≤xi,yi,ri≤108
  • 1≤ci≤1041≤ci≤104
    Output
    For every test case, you should output ‘Case #x: y’, where x indicates the case number and counts from 1 and y is the minimum cost.
    Sample Input
    1
    5
    0 0 1 5
    1 1 1 6
    0 1 1 7
    3 0 2 10
    5 0 1 4
    Sample Output
    Case #1: 15

这道题可为历经千辛万苦,之前没接触过强连通,就去自学了,看了很久才理解了,该题不认识强连通要先学好他,强连通用于求强连通分量图(改图中,两两之间可以相互抵达,如1->2->3->1)但你以为给他强连通一下就行了的话,就打错特错了,因为一个强连通图中的某个点也可能引爆其他强连通图的点啊(因为一个图中只要一个点炸,所有都会炸,所以这个被影响的图就不用管他 了),那么剩下不会被其他强连通图影响到的强连通图呢,就必须要在图内引爆一个点了,那么就引爆那个花费最少的,加起来就可以了。
对了只有不能成两两相同的图就只有一个点了,也把他当做强连通图吧

ac代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
#include<queue>
using namespace std;
const int N = 1100;
vector<int>g[N];
stack<int>s;
int n, m;
int time[N], flag[N], ji[N], sss[N],jiji[1011]; long long int s1[N], s2[N], s3[N], s4[N], v1[N], du[N];
long long int sum;int  kkk, a, b, c;
void asd(int x)//强连通
{
	time[x] = flag[x] = ++kkk;
	s.push(x);
	sss[x] = 1;//标记进栈的点
	for (int i = 0; i < g[x].size(); i++)
	{
		if (!flag[g[x][i]])
		{
			asd(g[x][i]);

			time[x] = min(time[x], time[g[x][i]]);
		}
		else if (sss[g[x][i]])
			time[x] = min(time[x], flag[g[x][i]]);

	}

	if (time[x] == flag[x])
	{
		
		while (1)
		{
			a = s.top();
			
			s.pop();
			sss[a]=0;//标记出栈的炸弹
			jiji[a]=b;//把点分入所属的图(从图0开始)
			
			if (x == a)break;
		}
			b++;
	}

}
void suodu()
{
	for (int i = 1; i <= m; i++)
	{
		for (int j = 0; j < g[i].size(); j++)
			if (jiji[i] != jiji[g[i][j]])
				du[jiji[g[i][j]]]++;(炸弹i可以引爆g[i][j],那么要是他们所属不同图的话,就可以通过i,引爆g[i][j]所属的图了)
	}for (int i = 1; i <= m; i++) {
		if (du[jiji[i]] == 0) {
			v1[jiji[i]] = min(v1[jiji[i]], s4[i]);
		}
	}//没法通过其他图来引爆的图就从自身内找一个最小的炸弹
		for (int i = 0; i < b; i++)
			if (du[i] == 0)
			{
				sum += v1[i];
			}
	
}
int main()
{
	
	cin >> n;
	c = 1;
	while (n--)
	{
		kkk = 0; sum = 0; b = 0;
		while (!s.empty())
			s.pop();
		memset(time, 0, sizeof(time));
		memset(flag, 0, sizeof(flag));
		memset(sss, 0, sizeof(sss));
			memset(du, 0, sizeof(du));
			memset(v1, 0x3f3f3f3f, sizeof(v1));
			for (int i = 0; i < N; i++)
			g[i].clear();

		cin >> m;
		for (int i = 1; i <= m; i++)
		{
			scanf("%lld%lld%lld%lld", &s1[i], &s2[i], &s3[i], &s4[i]);
		}
		for (int i = 1; i <= m; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				if (((s1[j] - s1[i])*(s1[j] - s1[i]) + (s2[j] - s2[i])*(s2[j] - s2[i])) <= (s3[i] * s3[i]) && i != j)
				{
					g[i].push_back(j);//存第i个炸弹可以影响到的炸弹
					
				}
			}
		}
		for (int i = 1; i <=m; i++)
		{
			if (!flag[i])
			{
				asd(i);
			}
		}
		suodu();
		cout << "Case #" << c << ": "<<sum<<endl ;
		c++;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值