HDU 5934 Bomb(tarjan缩点)

来源:互联网 发布:淘宝代销如何刷销量 编辑:程序博客网 时间:2024/06/07 18:08

题意:给你n(n<=1000)个炸弹(x, y, r, c),(x, y)是坐标,r是爆炸半径,c是引爆这个炸弹的花费。问你最少花费多少能引爆所有弹。


思路:枚举炸弹i j,如果i能引爆j,就i->j连一条边。然后跑下tarjan并缩点形成一个DAG,我们可以知道入度为0的是必须自身引爆,入度不为0的可以由其他炸弹来引爆,我们只需要求出每个入度为0的缩点中引爆所需的最小花费的那个炸弹,最后加起来求和即可。


代码:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 1e3+5;vector<int> g[maxn];struct node{    ll x, y, r, c;}a[maxn];int n, dfn[maxn], low[maxn], belong[maxn], in[maxn];int dfs_clock, scc_cnt;bool is[maxn];stack<int> s;priority_queue<ll, vector<ll>, greater<ll> > pq[maxn];void tarjan(int u){    dfn[u] = low[u] = ++dfs_clock;    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_cnt++;        while(1)        {            int x = s.top(); s.pop();            belong[x] = scc_cnt;            if(x == u) break;        }    }}void find_scc(){    while(!s.empty()) s.pop();    dfs_clock = scc_cnt = 0;    memset(belong, 0, sizeof(belong));    memset(dfn, 0, sizeof(dfn));    for(int i = 1; i <= n; i++)        if(!dfn[i])            tarjan(i);}void solve(){    memset(in, 0, sizeof(in));    memset(is, 0, sizeof(is));    for(int u = 1; u <= n; u++)        for(int i = 0; i < g[u].size(); i++)        {            int v = g[u][i];            if(belong[u] != belong[v])                in[belong[v]]++;        }    for(int i = 1; i <= scc_cnt; i++)        if(!in[i])            is[i] = 1;    for(int i = 1; i <= n; i++)        while(!pq[i].empty()) pq[i].pop();    for(int i = 1; i <= n; i++)    {        if(is[belong[i]])            pq[belong[i]].push(a[i].c);    }    ll ans = 0;    for(int i = 1; i <= scc_cnt; i++)        if(is[i])            ans += pq[i].top();    printf("%lld\n", ans);}int main(void){    int _, ca = 1;    cin >> _;    while(_--)    {        scanf("%d", &n);        for(int i = 1; i <= n; i++)            g[i].clear();        for(int i = 1; i <= n; i++)            scanf("%lld%lld%lld%lld", &a[i].x, &a[i].y, &a[i].r, &a[i].c);        for(int i = 1; i <= n; i++)            for(int j = 1; j <= n; j++)            {                if(i == j) continue;                if((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y) <= a[i].r*a[i].r)                    g[i].push_back(j);            }        find_scc();        printf("Case #%d: ", ca++);        solve();    }    return 0;}