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++;
}
}