Bomb
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 58 Accepted Submission(s): 27
Problem Description
There are
N
bombs needing exploding.
Each bomb has three attributes: exploding radius ri , position (xi,yi) and lighting-cost ci which means you need to pay ci 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.
Each bomb has three attributes: exploding radius ri , position (xi,yi) and lighting-cost ci which means you need to pay ci 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
T
, which indicates the number of test cases.
Every test case begins with an integers N , which indicates the numbers of bombs.
In the following N lines, the ith line contains four intergers xi , yi , ri and ci , indicating the coordinate of ith bomb is (xi,yi) , exploding radius is ri and lighting-cost is ci .
Limits
- 1≤T≤20
- 1≤N≤1000
- −108≤xi,yi,ri≤108
- 1≤ci≤104
Every test case begins with an integers N , which indicates the numbers of bombs.
In the following N lines, the ith line contains four intergers xi , yi , ri and ci , indicating the coordinate of ith bomb is (xi,yi) , exploding radius is ri and lighting-cost is ci .
Limits
- 1≤T≤20
- 1≤N≤1000
- −108≤xi,yi,ri≤108
- 1≤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
Source
Recommend
题意:给你n个炸弹,知道炸弹的坐标和爆炸半径,还有引爆它的费用,一个炸弹可以引爆另一个炸弹。问引爆所有炸弹的最小费用。
思路:n^2枚举一个炸弹是否可以引爆另一个炸弹,可以就建边,然后就是一个普通的强连通分量问题,跑一遍tarjan,找入度为0的强联通分量的最小费用加起来就好了。下面给代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
#include<utility>
#include<map>
#define maxn 1005
#define inf 0x3f3f3f3f
typedef long long LL;
using namespace std;
const int mod = 1e9 + 7;
int x[maxn], y[maxn], r[maxn], c[maxn], head[maxn], len, n;
int indeg[maxn]; //点的入度和出度数
int belong[maxn], low[maxn], dfn[maxn], scc, cnt;//dfn[]:遍历到u点的时间; low[]:u点可到达的各点中最小的dfn[v],ssc强连通分量数,belong表示该点在哪个联通块
int S[maxn], top, w[maxn];
bool vis[maxn];//v是否在栈中
struct node{
int to, next;
}Edge[maxn*maxn];
void tarjan(int u)
{
int v;
dfn[u] = low[u] = ++cnt;//开始时dfn[u] == low[u]
S[top++] = u;//不管三七二十一进栈
vis[u] = true;
for (int i = head[u]; ~i; i = Edge[i].next)
{
v = Edge[i].to;
if (dfn[v] == 0)//如果v点还未遍历
{
tarjan(v);//向下遍历
low[u] = low[u] < low[v] ? low[u] : low[v];//确保low[u]最小
}
else if (vis[v] && low[u] > dfn[v])//v在栈中,修改low[u]
low[u] = dfn[v];
}
if (dfn[u] == low[u])//u为该强连通分量中遍历所成树的根
{
++scc;
do
{
v = S[--top];//栈中所有到u的点都属于该强连通分量,退栈
vis[v] = false;
belong[v] = scc;
} while (u != v);
}
}
void solve()
{
scc = top = cnt = 0;
memset(dfn, 0, sizeof(dfn));
memset(vis, false, sizeof(vis));
for (int u = 1; u <= n; ++u)
if (dfn[u] == 0)
tarjan(u);
memset(indeg, 0, sizeof(indeg));
memset(w, inf, sizeof(w));
for (int u = 1; u <= n; ++u){
int x = belong[u];
w[x] = min(w[x], c[u]);
for (int i = head[u]; ~i; i = Edge[i].next)
{
int v = Edge[i].to;
if (x != belong[v])
{
indeg[belong[v]]++;
}
}
}
}
int main(){
int t;
scanf("%d", &t);
for (int tcase = 1; tcase <= t; tcase++){
scanf("%d", &n);
for (int i = 1; i <= n; i++){
scanf("%d%d%d%d", &x[i], &y[i], &r[i], &c[i]);
}
len = 0;
memset(head, -1, sizeof(head));
for (int i = 1; i <= n; i++){
for (int j = 1; j <= n; j++){
if (i == j)
continue;
if (pow(x[i] - x[j], 2) + pow(y[i] - y[j], 2) <= pow(r[i], 2)){
Edge[len].to = j;
Edge[len].next = head[i];
head[i] = len++;
}
}
}
solve();
LL ans = 0;
for (int i = 1; i <= scc; i++){
if (!indeg[i]){
ans += w[i];
}
}
printf("Case #%d: %lld\n", tcase, ans);
}
}