题意:
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;
}
继续加油~