Bomb
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 2118 Accepted Submission(s): 687
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
题意:
一个炸弹有坐标,引爆半径,引爆代价,一个炸弹爆了,如果半径里有另一个炸弹,也会爆炸。
问你要把所有炸弹引爆,代码最小是多少。
POINT:
先建图,A半径有B A-B,B半径有A,B-A,所以是单向的。
然后tarjan缩点,每一个强连通分量都求出其中最小代价的炸弹。
之后取入度为0的炸弹引爆,他们的代价总和即是最小的。
注意如果把所以边存下来,开两百万的数组会mle。
就在遍历一次就好了,不会tle。
#include <iostream>
#include <stdio.h>
#include <vector>
#include <math.h>
#include <string.h>
#include <stack>
using namespace std;
#define LL long long
const LL maxn = 2222;
const LL inf = 0x3f3f3f3f;
vector<LL>G[maxn];
LL n;
struct node
{
LL x,y,r,c;
} a[maxn];
LL DFN[maxn],low[maxn],inq[maxn],cor[maxn],Min[maxn];
LL cornum=0,tm=0;
stack<LL>q;
void init()
{
for(LL i=1; i<=n; i++) G[i].clear();
memset(DFN,0,sizeof DFN);
memset(low,0,sizeof low);
memset(inq,0,sizeof inq);
memset(cor,0,sizeof cor);
// memset(Min,inf,sizeof Min);
cornum=tm=0;
while(!q.empty())
{
q.pop();
}
}
void tarjan(LL u)
{
DFN[u]=low[u]=++tm;
inq[u]=1;
q.push(u);
for(LL i=0; i<G[u].size(); i++)
{
LL v=G[u][i];
if(DFN[v]==0)
{
tarjan(v);
if(low[u]>low[v]) low[u]=low[v];
}
else if(inq[v]&&low[u]>DFN[v])
{
low[u]=DFN[v];
}
}
if(DFN[u]==low[u])
{
cornum++;
LL v;
Min[cornum]=inf;
do
{
v=q.top();
Min[cornum]=min(Min[cornum],a[v].c);
cor[v]=cornum;
inq[v]=0;
q.pop();
}
while(v!=u);
}
}
int main()
{
LL T;
scanf("%lld",&T);
LL p=0;
while(T--)
{
scanf("%lld",&n);
init();
for(LL i=1; i<=n; i++)
{
scanf("%lld %lld %lld %lld",&a[i].x,&a[i].y,&a[i].r,&a[i].c);
}
for(LL i=1; i<=n; i++)
{
for(LL j=1; j<=n; j++)
{
if(i!=j)
{
double l=sqrt(1.0*(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
if(a[i].r>=l)
{
G[i].push_back(j);
}
if(a[j].r>=l)
{
G[j].push_back(i);
}
}
}
}
for(LL i=1; i<=n; i++)
{
if(DFN[i]==0)
{
tarjan(i);
}
}
LL du[maxn];
memset(du,0,sizeof du);
for(LL i=1; i<=n; i++)
{
for(LL j=1; j<=n; j++)
{
if(i!=j)
{
double l=sqrt(1.0*(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
if(cor[i]!=cor[j])
{
if(a[i].r>=l)
{
du[cor[j]]++;
}
if(a[j].r>=l)
{
du[cor[i]]++;
}
}
}
}
}
LL ans=0;
for(LL i=1;i<=cornum;i++){
if(du[i]==0){
ans+=Min[i];
}
}
printf("Case #%lld: ",++p);
printf("%lld\n",ans);
}
return 0;
}