HDU 5934 Bomb(强连通分量缩点)

题目:https://vjudge.net/contest/338569#problem/P

显然可以想到引爆花费最小需要选择能引爆尽量多的,如果A能引爆B,B能引爆C,一定是引爆A最优。

如果有一些点可以相互引爆,那么就引爆这些点里花费最小的。

“能互相引爆”这显然是一个强连通分量,因此用tarjan求强连通分量之后,对于每个拓扑序最开头(入度为0)的连通分量,选择花费最小的进行引爆,即可求出答案。

ac代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e3 + 5;

int _, n, kase;

struct Point {
    ll x, y, r;
    int c;
} p[maxn];

vector<int> G[maxn];

ll getDis(const Point &a, const Point &b) {
    return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}

int dfn[maxn], low[maxn], scc[maxn], tot, scc_cnt;
stack<int> st;

void tarjan(int x) {
    dfn[x] = low[x] = ++tot;
    st.push(x);
    for (auto v:G[x]) {
        if (!dfn[v]) {
            tarjan(v);
            low[x] = min(low[x], low[v]);
        } else if (!scc[v]) {
            low[x] = min(low[x], dfn[v]);
        }
    }
    if (dfn[x] == low[x]) {
        ++scc_cnt;
        int v;
        while (v != x) {
            v = st.top();
            st.pop();
            scc[v] = scc_cnt;
        }
    }
}

void findScc() {
    tot = scc_cnt = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(scc, 0, sizeof(scc));
    for (int i = 1; i <= n; ++i) {
        if (!dfn[i]) {
            tarjan(i);
        }
    }
}

int deg[maxn], cost[maxn];

int main() {
    scanf("%d", &_);
    while (_--) {
        memset(deg, 0, sizeof(deg));
        memset(cost, 0x3f, sizeof(deg));
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf("%lld%lld%lld%d", &p[i].x, &p[i].y, &p[i].r, &p[i].c);
            p[i].r = p[i].r * p[i].r;
        }
        for (int i = 1; i <= n; ++i) {
            G[i].clear();
            for (int j = 1; j < i; ++j) {
                if (getDis(p[i], p[j]) <= p[i].r) {
                    G[i].push_back(j);
                }
                if (getDis(p[j], p[i]) <= p[j].r) {
                    G[j].push_back(i);
                }
            }
        }

        findScc();

        for (int i = 1; i <= n; ++i) {
            for (auto v:G[i]) {
                if (scc[v] != scc[i]) {
                    ++deg[scc[v]];
                }
            }
            cost[scc[i]] = min(cost[scc[i]], p[i].c);
        }

        int ans = 0;
        for (int i = 1; i <= scc_cnt; ++i) {
            if (!deg[i]) {
                ans += cost[i];
            }
        }
        printf("Case #%d: %d\n", ++kase, ans);
    }
    return 0;
}

发布了156 篇原创文章 · 获赞 20 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/Cymbals/article/details/102780731
今日推荐