HDU5934 强连通分量

本文介绍了一种解决特定问题的方法:通过计算炸弹之间的距离关系建立连接,并利用强连通分量的概念找到引爆整个系统的最小花费。通过对点进行拓扑排序和使用并查集维护,最终确定引爆整个网络所需的最低成本。

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

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5934

  1. 根据距离关系建边
  2. 对于强连通分量来说,只需引爆话费最小的炸弹即可引爆整个强连通分量
  3. 将所有的强连通分量缩成点,我们就得到了一棵树,我们只需要引爆树根的炸弹即可
  4. 我们可以处理出每个点所属的强连通分量的拓扑序,或者说染色法,把属于同一个强连通分量的点标上同一个数字
  5. 处理完强连通分量后,我们不需要建树,我们可以用并查集来维护,更好的办法是统计每个点的入度,入读为0即为根节点
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxv = 1111;
     5 int V;//总共点的个数 
     6 vector<int> g[maxv];
     7 vector<int> rg[maxv];
     8 vector<int> vs;
     9 bool used[maxv];
    10 int cmp[maxv];//保存拓扑序 
    11 ll cost[maxv];//每个拓扑序的话费 
    12 ll x[1111],y[1111],r[1111],c[1111];
    13 ////scc
    14 void dfs(int v){
    15     used[v] = true;
    16     for(int i = 0;i<g[v].size();i++)
    17         if(!used[g[v][i]])
    18             dfs(g[v][i]);
    19     vs.push_back(v);
    20 }
    21 void rdfs(int v,int k){
    22     used[v] = true;
    23     cmp[v] = k;
    24     cost[k] = min(cost[k],c[v]);//处理出每个强连通分量的最小话费 
    25     for(int i = 0;i<rg[v].size();i++)
    26         if(!used[rg[v][i]])
    27             rdfs(rg[v][i],k);
    28 }
    29 int scc(){
    30     memset(used,0,sizeof(used));
    31     vs.clear();
    32     for(int v = 1;v<=V;v++)//这里要注意,下标是从0开始还是从1开始 
    33         if(!used[v])
    34             dfs(v);
    35     memset(used,0,sizeof(used));
    36     int k = 1;
    37     for(int i = vs.size()-1;i>=0;i--)
    38         if(!used[vs[i]])
    39             rdfs(vs[i],k++);
    40     return k;
    41 }
    42 //////
    43 void addedge(int i,int j){
    44     ll dis = (y[i]-y[j])*(y[i]-y[j])+(x[i]-x[j])*(x[i]-x[j]);
    45     if(dis <= r[i]*r[i]){
    46         g[i].push_back(j);
    47         rg[j].push_back(i);    
    48     }
    49     if(dis <= r[j]*r[j]){
    50         g[j].push_back(i);
    51         rg[i].push_back(j);
    52     }
    53 }
    54 //////
    55 int du[1111];
    56 int main(){
    57     int t;
    58     cin >> t;
    59     int cas = 1;
    60     while(t--){
    61         int n;
    62         cin >> n;
    63         V = n;
    64         memset(cost,0x3f3f3f3f,sizeof(cost));
    65         for(int i = 1;i<=n;i++){
    66             g[i].clear();
    67             rg[i].clear();
    68         }
    69         for(int i = 1;i<=n;i++){
    70             scanf("%I64d%I64d%I64d%I64d",&x[i],&y[i],&r[i],&c[i]);
    71             for(int j = 1;j<i;j++){
    72                 addedge(i,j);
    73             }
    74         }
    75         int k = scc();
    76         memset(du,0,sizeof(du));
    77         for(int i = 1;i<=n;i++)
    78             for(int j = 0;j<g[i].size();j++)
    79                 if(cmp[i] != cmp[g[i][j]])//拓扑序不同,度数加1 
    80                     du[cmp[g[i][j]]]++;
    81         ll ans = 0;
    82         for(int i = 1;i<k;i++)
    83             if(du[i] == 0)
    84                 ans += cost[i] ;
    85         printf("Case #%d: %I64d\n",cas++,ans);
    86     }
    87     return 0;
    88 }

     

转载于:https://www.cnblogs.com/zqy123/p/6020009.html

### 使用Tarjan算法计算强连通分量数量 #### 算法原理 Tarjan算法通过深度优先搜索(DFS)遍历有向图中的节,记录访问顺序和低链值(low-link value),从而识别出所有的强连通分量。当发现一个节的访问序号等于其最低可达节编号时,表明找到了一个新的强连通分量。 #### 时间复杂度分析 该方法的时间效率取决于存储结构的选择。对于采用邻接表表示的稀疏图而言,整体性能更优,能够在线性时间内完成操作,即O(n+m)[^4];而针对稠密图则可能退化至平方级别(O(n²))。 #### 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、付费专栏及课程。

余额充值