Bomb
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 95 Accepted Submission(s): 46
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
题意:有n个炸弹,每个炸弹有三个属性,位置,爆炸半径,手动爆炸花费,如果A爆炸,在A的爆炸范围内的炸弹都会爆炸,问使所有炸弹爆炸
最小花费是多少;
如果A能引爆B,那么在A B之间建一条单向边A->B ,然后用Tarjan算法缩点,缩点过程把相连通分量内的那个花费最小的炸弹求出并保存,然后用缩点建立新图,每次引爆入度为0的炸弹即可,
如何建立新图?u->v, belong[u]!=belong[v],说明u v不在同一个分量里,那么 belong[u]->belong[v]建立新边,在此题中不必真正的建立新图,只要求入度就好了,
AC代码:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int maxn=1005;
struct node
{
LL x,y,r;
int c;
} d[maxn];
struct Edge
{
int to,next;
} edge[maxn*maxn*2];
int tot,head[maxn];
int vis[maxn],in[maxn];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
LL D(int i,int j)
{
return (d[i].x-d[j].x)*(d[i].x-d[j].x)+(d[i].y-d[j].y)*(d[i].y-d[j].y);
}
int num[maxn];///每个联通分量含有点的个数
int g[maxn],f[maxn];///f入度,g出度
int dfn[maxn],low[maxn],v[maxn],s[maxn],b[maxn];
int n,cnt=0,times,t;
int c[maxn];
void Tarjan(int x)
{
int y,i;
times++;
t++;
dfn[x]=low[x]=times;
v[x]=1;
s[t]=x;
for (i=head[x]; i!=-1; i=edge[i].next)
{
y=edge[i].to;
if (v[y]==0)
{
Tarjan(y);
low[x]=min(low[x],low[y]);
}
if (v[y]==1)
low[x]=min(low[x],dfn[y]);
}
if (dfn[x]==low[x])
{
cnt++;
do
{
y=s[t--];
c[cnt]=min(c[cnt],d[y].c);///保存cnt 分量里的最小花费
b[y]=cnt;///属于哪个强连通分量
v[y]=2;
}
while (y!=x);
}
}
LL solve(int n)
{
times=0;
t=0;
cnt=0;///连通分量个数
memset(dfn,0,sizeof(dfn));
memset(v,0,sizeof(v));
memset(c,inf,sizeof(c));
for(int i=0; i<n; i++)
if(!dfn[i])
Tarjan(i);
for(int u=0;u<n;u++)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(b[u]!=b[v])///求新图入度
in[b[v]]++;
}
}
LL ans=0;
for(int i=1;i<=cnt;i++)///cnt 从1开始
{
if(in[i]==0)
ans+=c[i];
}
return ans;
}
int main()
{
int T;
int n;
LL temp;
scanf("%d",&T);
for(int cas=1; cas<=T; cas++)
{
scanf("%d",&n);
init();
memset(in,0,sizeof(in));
for(int i=0; i<n; i++)
{
scanf("%lld%lld%lld%lld",&d[i].x,&d[i].y,&d[i].r,&d[i].c);
}
///建立新图
for(int i=0; i<n; i++)
{
for(int j=i+1; j<n; j++)
{
temp=D(i,j);
if(d[i].r*d[i].r>=temp)
add(i,j);
if(d[j].r*d[j].r>=temp)
add(j,i);
}
}
LL ans=solve(n);
printf("Case #%d: %d\n",cas,ans);
}
return 0;
}