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

本文深入探讨了如何使用Tarjan算法求解强连通分量,并结合拓扑排序解决引爆点费用最小化问题。通过具体实例,讲解了如何将问题抽象成图论模型,运用算法高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目: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;
}

内容概要:文章详细介绍了ETL工程师这一职业,解释了ETL(Extract-Transform-Load)的概念及其在数据处理中的重要性。ETL工程师负责将分散、不统一的数据整合为有价值的信息,支持企业的决策分析。日常工作包括数据整合、存储管理、挖掘设计支持和多维分析展现。文中强调了ETL工程师所需的核心技能,如数据库知识、ETL工具使用、编程能力、业务理解能力和问题解决能力。此外,还盘了常见的ETL工具,包括开源工具如Kettle、XXL-JOB、Oozie、Azkaban和海豚调度,以及企业级工具如TASKCTL和Moia Comtrol。最后,文章探讨了ETL工程师的职业发展路径,从初级到高级的技术晋升,以及向大数据工程师或数据产品经理的横向发展,并提供了学习资源和求职技巧。 适合人群:对数据处理感兴趣,尤其是希望从事数据工程领域的人士,如数据分析师、数据科学家、软件工程师等。 使用场景及目标:①了解ETL工程师的职责和技能要求;②选择适合自己的ETL工具;③规划ETL工程师的职业发展路径;④获取相关的学习资源和求职建议。 其他说明:随着大数据技术的发展和企业数字化转型的加速,ETL工程师的需求不断增加,尤其是在金融、零售、制造、人工智能、物联网和区块链等领域。数据隐私保护法规的完善也使得ETL工程师在数据安全和合规处理方面的作用更加重要。
### 使用Tarjan算法计算强连通分量数量 #### 算法原理 Tarjan算法通过深度优先搜索(DFS)遍历有向图中的节,记录访问顺序和低链值(low-link value),从而识别出所有的强连通分量。当发现一个节的访问序号等于其最低可达节编号时,表明找到了一个新的强连通分量。 #### 时间复杂度分析 该方法的时间效率取决于存储结构的选择。对于采用邻接表表示的稀疏图而言,整体性能更优,能够在线性时间内完成操作,即O(n+m)[^4];而针对稠密图则可能退化至平方级别(O())。 #### Python代码实现 下面给出一段Python程序用于演示如何基于NetworkX库构建并处理带权无环图(DAG),进而求解其中存在的全部SCC及其总数: ```python import networkx as nx def tarjan_scc(graph): index_counter = [0] stack = [] lowlinks = {} index = {} result = [] def strongconnect(node): # Set the depth index for this node to be the next available incrementing counter. index[node] = index_counter[0] lowlinks[node] = index_counter[0] index_counter[0] += 1 stack.append(node) try: successors = graph.successors(node) except AttributeError: successors = graph.neighbors(node) for successor in successors: if successor not in lowlinks: strongconnect(successor) lowlinks[node] = min(lowlinks[node], lowlinks[successor]) elif successor in stack: lowlinks[node] = min(lowlinks[node], index[successor]) if lowlinks[node] == index[node]: scc = set() while True: current_node = stack.pop() scc.add(current_node) if current_node == node: break result.append(scc) for node in graph.nodes(): if node not in lowlinks: strongconnect(node) return result if __name__ == "__main__": G = nx.DiGraph() # Create a directed graph object using NetworkX library edges_list = [(1, 2),(2, 3),(3, 1)] # Define edge list according to sample input data from hdu1269 problem statement[^5] G.add_edges_from(edges_list) components = tarjan_scc(G) print(f"Number of Strongly Connected Components found: {len(components)}") ``` 此段脚本定义了一个名为`tarjan_scc()`的功能函数接收网络对象作为参数,并返回由集合组成的列表形式的结果集,每个子集中包含了构成单个SCC的所有顶。最后部分展示了创建测试用DAG实例的过程以及调用上述功能获取最终答案的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值