您的位置:首页 > 其它

2016ccpc杭州赛 hdu 5934 B.Bomb

2016-10-29 22:21 417 查看


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.

 

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

 

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

2016年中国大学生程序设计竞赛(杭州)

 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  5947 5946 5945 5944 5943 
题意:给你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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: