Bomb
题目传送门
题意:有n个炸弹,给出这些炸弹的坐标,爆炸半径和爆炸花费,如果在这个炸弹的爆炸范围内有其他炸弹,那么这个炸弹也能被引爆并且不需要花费,求使得所有炸弹爆炸所需的最小花费。
思路:我们可以按照炸弹的位置距离大小关系建图,当炸弹i可以引爆炸弹j时,则有i->j。如此我们就可以通过强连通找到联通块,该连通块内的炸弹可以互相引爆。那么所有连通块内引爆炸弹所需的最小花费之和是否是答案?不是,这里我们忽略了一种情况,则是在两个连通块其中的一个连通块中有一个炸弹是可以引爆另一个连通块,如此一来,另一个连通块则无需花费。这时候我们就需要强连通缩点了,当其缩点后,其入度为0的点就是我们需要引爆的连通块。
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <algorithm>
#include <functional>
#define inf 10000000
using namespace std;
typedef long long ll;
const int MAXN=5e6+10;
const int MAX=4000+10;
const double eps=1e-6;
struct NODE{
ll x,y,r;
int cost;
}node[MAX];
struct EDGE{
int u,v,next;
}edge[MAXN];
int n,num,Time,scc,ans,flag=1;
int first[20000],dfn[MAX],low[MAX],belong[MAX];
bool vis[MAX];
int du[MAX],save[MAX];
stack<int>q;
void init(){
ans=scc=num=0;
Time=1;
fill(save,save+n+1,inf);
memset(vis,0,sizeof(vis));
memset(du,0,sizeof(du));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(first,-1,sizeof(first));
while(q.size()) q.pop();
}
void addedge(int u,int v){
edge[num].u=u;
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
}
void tarjan(int u){
dfn[u]=low[u]=Time++;
q.push(u);
vis[u]=1;
for(int i=first[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
int v;
do{
v=q.top();q.pop();
vis[v]=0;
belong[v]=scc;
}while(u!=v);
scc++;
}
}
void get_scc(){
for(int i=1;i<=n;i++){
if(!dfn[i])
tarjan(i);
}
}
void sovle(){
get_scc();
for(int i=0;i<num;i++){
int u=edge[i].u;
int v=edge[i].v;
if(belong[u]!=belong[v]){
du[belong[v]]++;
}
}
for(int i=1;i<=n;i++){
if(du[belong[i]]==0){
save[belong[i]]=min(save[belong[i]],node[i].cost);
}
}
for(int i=0;i<scc;i++){
if(du[i]==0)
ans+=save[i];
}
printf("Case #%d: %d\n",flag++,ans);
}
int main(){
#ifdef ONLINE_JUDGE
#else
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
init();
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld%d",&node[i].x,&node[i].y,&node[i].r,&node[i].cost);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) continue;
ll far=(node[i].x-node[j].x)*(node[i].x-node[j].x);
far+=(node[i].y-node[j].y)*(node[i].y-node[j].y);
if(far<=node[i].r*node[i].r){
addedge(i,j);
}
}
}
sovle();
}
return 0;
}