题意:
N个炸弹都有一个坐标一个爆炸半径以及一个引爆花费,如果一个炸弹在另一个炸弹的爆炸范围内,则引爆另一个炸弹,可以导致当前炸弹也爆炸,如果当前炸弹的爆炸范围有其它未炸的炸弹,那么也能导致这些炸弹爆炸,以此联动。
思路:
如果i炸弹的爆炸范围内有j炸弹,则建有向边i->j,然后缩一下点,每个强连通分量内只要引爆一个,其它都会炸,所以把最小的花费给这个强连通分量,最后我们只需要引爆所有入度为0的强连通分量,且花费最小。
代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const ll bas = 1001;
const int maxn = 1005;
const int maxm = 1000005;
struct node {int u, v, next;} edge[maxm];
int no, head[maxn];
int _index, low[maxn], dfn[maxn], S[maxn], top, vis[maxn];
int deg[maxn];
int bcc[maxn], cnt;
queue<int> q;
int n, m;
/*unordered_*/set<ll> _hash;
inline void init()
{
no = 0; _hash.clear();
memset(head, -1, sizeof head);
_index = top = 0; cnt = 0;
memset(dfn, 0, sizeof dfn);
memset(bcc, 0, sizeof bcc);
memset(deg, 0, sizeof deg);
}
inline void add(int u, int v)
{
edge[no].u = u, edge[no].v = v;
edge[no].next = head[u];
head[u] = no++;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++_index;
S[++top] = u;
vis[u] = 1;
for(int k = head[u]; k != -1; k = edge[k].next)
{
int v = edge[k].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])
{
++cnt;
do
{
bcc[S[top]] = cnt;
vis[S[top--]] = 0;
}
while(S[top+1] != u);
}
}
struct point
{
int x, y, c, r;
} aw[maxn];
int val[maxn];
ll dis2(point p1, point p2)
{
return 1ll*(p1.x-p2.x)*(p1.x-p2.x)+1ll*(p1.y-p2.y)*(p1.y-p2.y);
}
int main()
{
//freopen("in.txt", "r", stdin);
int t, u, v;
scanf("%d", &t);
for(int _ = 1; _ <= t; ++_)
{
scanf("%d", &n); init();
for(int i = 1; i <= n; ++i)
scanf("%d %d %d %d", &aw[i].x, &aw[i].y, &aw[i].r, &aw[i].c);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
if(i != j)
{
ll d = dis2(aw[i], aw[j]);
if(d <= 1ll*aw[i].r*aw[i].r) add(i,j);
}
for(int i = 1; i <= n; ++i)
if(!dfn[i]) tarjan(i);
for(int i = 0; i < no; ++i)
{
int u = edge[i].u, v = edge[i].v;
if(bcc[u] != bcc[v] && _hash.find(bas*bcc[u]+bcc[v]) == _hash.end())
{
_hash.insert(bas*bcc[u]+bcc[v]);
++deg[bcc[v]];
}
}
memset(val, 0x3f, sizeof val);
for(int i = 1; i <= n; ++i)
val[bcc[i]] = min(val[bcc[i]], aw[i].c);
ll ans = 0;
for(int i = 1; i <= cnt; ++i)
if(deg[i] == 0) ans += val[i];
printf("Case #%d: %lld\n", _, ans);
}
return 0;
}
继续加油~

本文介绍了一个涉及多个炸弹的引爆问题,通过建立有向图并利用强连通分量的概念来解决如何以最小成本引爆所有炸弹的问题。文章详细阐述了算法实现步骤,并提供了完整的代码示例。
227

被折叠的 条评论
为什么被折叠?



