您的位置:首页 > 其它

【HDU】5934 Bomb 强连通分量+缩点

2017-10-18 19:55 363 查看
http://acm.hdu.edu.cn/showproblem.php?pid=5934

N个炸弹。

每个炸弹有坐标x,y,爆炸范围和引爆花费,若一个炸弹的爆炸范围内有另一个炸弹,那么如果该炸弹爆炸,就会引爆所有爆炸范围内的炸弹,求让所有炸弹爆炸的最小花费。

先n^2,把每个炸弹爆炸范围内的炸弹都连一条有向边,然后再找强连通分量缩点,这样会形成多个DAG,然后对于每个DAG找一个入度为0的点,找这个入度为0的点里面耗费最小的去引爆。

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int maxn = 1005;
const int maxm = maxn*maxn;
typedef long long LL;

struct Bomb
{
LL x,y,r;
int c;
}b[maxn];

int n;
vector <int> G[maxn];
stack <int> S;
int in[maxn];    //强连通分量i的入度
int dfn[maxn];   //dfs访问次序
int low[maxn];  //能追溯的最早次序
int minCost[maxn]; //引爆第i个缩点后的最小花销
int Belong[maxn];  //第i个点属于第Belong[i]个强联通分量
int id,scc;

void tarjan(int u)
{
dfn[u]=low[u]=++id;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else
if(!Belong[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u])
{
scc++;
while(1)
{
int tmp=S.top();
S.pop();
Belong[tmp]=scc;
minCost[scc]=min(minCost[scc],b[tmp].c);
if(tmp==u)break;
}
}
}

void find_scc()
{
id=scc=0;
memset(Belong,0,sizeof(Belong));
memset(dfn,0,sizeof(dfn));

for(int i=0;i<=n;i++){
minCost[i]=999999999;
}

for(int i=0;i<n;i++){
if(!dfn[i]){
tarjan(i);
}
}
}

int solve(){

memset(in,0,sizeof(in));
for (int i=0;i<n;i++){
for (int j=0;j<G[i].size();j++){
if (Belong[i]!=Belong[G[i][j]]){
in[Belong[G[i][j]]]++;
}
}
}

int res=0;
for(int i=1;i<=scc;i++){
if(in[i]==0){
res+=minCost[i];
}
}

return res;
}

bool ok(Bomb a,Bomb b)
{
return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y)*1.0)<=a.r*1.0;
}

int main(){

int t;
cin >> t;
for(int cnt=1;cnt<=t;cnt++)
{
cin >> n;
for(int i=0;i<n;i++){
scanf("%lld%lld%lld%d",&b[i].x,&b[i].y,&b[i].r,&b[i].c);
}
memset(G,0,sizeof(G));
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
if (i!=j&&ok(b[i],b[j])){
G[i].push_back(j);
}
}
}
find_scc();
printf("Case #%d: %d\n",cnt,solve());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: