1.题目链接。题目大意:n个炸弹,每个炸弹具有四个参数,分别是这个炸弹的位置(x,y),爆炸时的半径,以及引爆它的费用。引爆炸弹的规则是,当一个炸弹被引爆,在他爆炸半径内的炸弹也会被引爆。问引爆这n个炸弹需要的最少费用。
2.如果一个炸弹能够引爆另外一个炸弹,我们连一条指向被引爆的炸弹的有向边。这样n^2建图之后,显然是一个有向图。在这个有向图中,所有的强连通分量其实可以被看做一个点,因为只要引爆其中任意一个这个强连通分量中的所有炸弹都将被引爆,所以Tarjan缩点,缩点之后这个点的费用是这个强连通分量里费用最小的那个。然后,怎么统计答案?其实很简单,只需要统计有多少个入度为0的强连通分量即可,因为入读为零,没有人来引爆它,只能花费费用引爆。所以这个题完事。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define met(a,b) memset(a,b,sizeof a)
typedef long long ll;
using namespace std;
const int N = 1005;
const int M = 24005;
int vis[N], dfn[N], low[N], head[N], stack1[N], num[N], in[N];
ll cost[N];
int n, m, tot, son, maxn, tim, top, cut;
ll ans;
struct EDG { int to, next; }edg[N * N];
struct node { ll x, y, r, c; }a[N];
bool cmp(node f, node g) { return f.c < g.c; }
void add(int u, int v) {
edg[tot].to = v; edg[tot].next = head[u]; head[u] = tot++;
}
void init() {
met(head, -1);
tot = tim = top = cut = 0;
met(vis, 0);
met(edg, 0);
met(in, 0);
met(cost, inf);
met(stack1, 0); met(num, 0); met(dfn, 0); met(low, 0);
}
void Tarjan(int u) {
int v;
low[u] = dfn[u] = ++tim;
stack1[top++] = u;
vis[u] = 1;
for (int e = head[u]; e != -1; e = edg[e].next) {
v = edg[e].to;
if (!dfn[v]) {
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u])
{
cut++;
do {
v = stack1[--top];
num[v] = cut;
cost[cut] = min(cost[cut], a[v].c);
vis[v] = 0;
} while (u != v);
}
}
double dis(node a, node b)
{
return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}
int main()
{
int T;
scanf("%d", &T);
for (int ca = 1; ca <= T; ca++)
{
init();
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lld%lld%lld%lld", &a[i].x, &a[i].y, &a[i].r, &a[i].c);
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (dis(a[i], a[j]) <= a[i].r)add(i, j);
}
}
for (int i = 1; i <= n; i++)if (!dfn[i])Tarjan(i);
for (int i = 1; i <= n; i++)
{
for (int j = head[i]; j!=-1; j = edg[j].next)
{
int v = edg[j].to;
if (num[i] != num[v])in[num[v]]++;
}
}
ll ans = 0;
for (int i = 1; i <= cut; i++)
{
if (!in[i])ans += cost[i];
}
printf("Case #%d: %lld\n", ca, ans);
}
}