题干:
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
题目大意:
现有N颗炸弹急需引爆。每颗炸弹有三个属性:爆炸半径ri,炸弹位置(xi, yi),还有起爆费用ci,即你需要花费ci才能引爆这个炸弹。如果一颗未引爆的炸弹在另一颗炸弹的爆炸半径边缘或者其中,则会被连锁引爆。此时你已得知所有炸弹的属性,用最小的花费引爆所有炸弹吧。
解题报告:
强连通分量 + 缩点。先跑一遍Tarjan把所有可以互相引爆的炸弹缩成一个点,也就是说这些只需要看这些小集合之间的关系,这些小集合之间由于不存在互相引爆的情况,所以构成一个DAG图,那么我们引爆所有入度为0的集合就可以了,对于集合内部,我们选择那个爆炸燃烧最小的花费就行了。
AC代码:
using namespace std;
const int MAX = 2e4 + 5;
struct Point {
ll x, y, r, c;
} p[MAX];
struct Edge {
int fr,to,ne;
} e[2000010];
int head[MAX],id,cnt,tot,index;
int n;
int DFN[MAX],vis[MAX],stk[MAX],LOW[MAX],bel[MAX],in[MAX];
bool ok(int u, int v) {
double res = sqrt(((p[u].x - p[v].x) * (p[u].x - p[v].x) + (p[u].y - p[v].y) * (p[u].y - p[v].y)));
if(res <= p[u].r) return 1;
return 0;
}
void add(int u, int v) {
e[++tot].to = v;
e[tot].ne = head[u];
head[u] = tot;
}
void Tarjan(int x) {
DFN[x] = LOW[x] = ++id;
stk[++index] = x;
vis[x] = 1;
for(int i = head[x]; i!=-1; i = e[i].ne) {
if(!DFN[e[i].to]) {
Tarjan(e[i].to);
LOW[x] = min(LOW[x],LOW[e[i].to]);
}
else if(vis[e[i].to]) {
LOW[x] = min(LOW[x],DFN[e[i].to]);
}
}
if(LOW[x] == DFN[x]) {
cnt++;
while(1) {
int tmp = stk[index];
index--;
bel[tmp] = cnt;
vis[tmp]=0;
if(tmp == x) break;
}
}
}
void init() {
for(int i = 1; i<=n; i++) {
head[i]=-1;
DFN[i]=LOW[i]=bel[i]=vis[i]=in[i]=0;
}
cnt=tot=id=index=0;
}
int main() {
int t,iCase=0;
cin>>t;
while(t--) {
scanf("%d",&n);
init();
for(int i = 1; i <= n; i++) scanf("%lld%lld%lld%lld", &p[i].x, &p[i].y, &p[i].r, &p[i].c);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(i == j) continue;
if(ok(i, j)) 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 = e[j].ne) {
int u = i,v = e[j].to;
if(bel[u]!=bel[v]) {
in[bel[v]]++;
}
}
}
ll ans = 0;
for(int i = 1; i<=cnt; i++) {
if(in[i]!=0) continue;
ll minn = 0x3f3f3f3f;
for(int j = 1; j<=n; j++) {
if(bel[j] == i) {
minn = min(minn,p[j].c);
}
}
ans += minn;
}
printf("Case #%d: %d\n", ++iCase, ans);
}
return 0 ;
}