hdu 5723 最小生成树+dfs (多校)

本文介绍了一种求解最小生成树及其任意两点间距离期望的算法。通过使用Kruskal算法找到最小生成树,并利用DFS遍历计算所有点对间的距离总和,最终得到期望值。

题意:
给出一个图,求最小生成树,然后求一下最小生成树的任意两点之间距离的期望。n<=100000,m<=1000000
分析:
期望=任意两点之间的距离和/(n*(n-1)/2)
每条边对距离和的贡献就是这条边的两端的点数之积,可以任选一个点dfs,那么一条边的贡献就是子结点和父结点两端的点数之积,子结点一端的点数是nun,那么父节点一端的点数就是n-num。贡献就是num*(n-num)*w.

#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
typedef long long ll;
typedef pair<int,int>pii;
const int INF=1e9;
const int N=100000+9;
const int M=1000000+9;
struct node
{
    int u,v,w;
    bool operator<(const node& rhs)const{
        return w<rhs.w;
    }
};
node q[M];
vector<pii>e[N];
double sum;
ll ans;
int n,m,fa[M];
int findfa(int x){return fa[x]==x?x:fa[x]=findfa(fa[x]);}
int dfs(int u,int f)
{
    int num=0;
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i].first;
        if(v==f)continue;
        int tmp=dfs(v,u);
        num+=tmp;
        sum+=1.0*e[u][i].second*tmp*(n-tmp);
    }
    return num+1;
}
void init()
{
    for(int i=1;i<=n;i++)fa[i]=i,e[i].clear();
    ans=0;
    sum=0;
}
int main()
{
    //freopen("f.txt","r",stdin);
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].w);
        }
        sort(q,q+m);
        for(int i=0;i<m;i++){
            int x=findfa(q[i].u),y=findfa(q[i].v);
            if(x!=y){
                fa[x]=y;
                ans+=q[i].w;
                e[q[i].u].push_back(mp(q[i].v,q[i].w));
                e[q[i].v].push_back(mp(q[i].u,q[i].w));
            }
        }
        dfs(1,0);
        printf("%lld %.2lf\n",ans,sum/n/(n-1)*2);
    }

    return 0;
}

<think>嗯,用户想学习最小生成树算法,准备数学建模比赛,需要相关的学习资料。首先,我得回顾一下最小生成树的基础知识,确保自己理解正确。最小生成树主要有Prim和Kruskal两种算法,对吧?根据引用里的内容,Prim算法是通过选择连接已选集合和未选集合的最小边来逐步构建树,而Kruskal则是按边权重排序,逐步合并集合,避免环的出现。这些内容在引用[2]和[3]里都有提到,用户可能需要详细的步骤和实现。 接下来,用户可能需要具体的代码示例,比如Python或Matlab的实现。引用[4]提到Matlab中可以使用sparse函数,但默认是Prim,而用户可能需要比较不同算法的效率。这时候可能需要给出Matlab和Python的代码片段,帮助用户理解如何实现这些算法。 然后,用户的需求是准备数学建模比赛,所以实际应用案例和注意事项也很重要。比如在通信网络设计、交通规划中的应用,如何将实际问题转化为图论模型,这些都需要结合引用中的例子来展开。同时,引用[1]提到Dijkstra、DFS/BFS等其他图算法,可能需要指出这些算法与最小生成树的区别和联系,帮助用户全面理解。 用户可能还需要学习资料推荐,比如教材、在线课程和实战题目。要确保推荐的资源权威且适合数学建模比赛,比如《算法导论》或者OI Wiki,以及LeetCode的相关题目。此外,比赛中的注意事项,比如数据规模对算法选择的影响、验证正确性的方法,这些都需要提到,引用里的内容也提到了这些点。 在组织回答时,需要结构清晰,分点讲解,确保用户能一步步掌握。可能还要比较Prim和Kruskal的优缺点,比如Kruskal适合稀疏图,而Prim适合稠密图,这会影响比赛中的选择。同时,强调数学建模中的问题转化能力,如何将实际问题抽象成图结构,这也是关键点。 最后,生成相关问题时要围绕用户可能遇到的后续疑问,比如算法比较、复杂度分析、应用实例等,这样用户可以有进一步的学习方向。确保引用正确,每个引用对应到具体的内容,比如引用[3]解释Prim的步骤,引用[2]解释Kruskal的过程,引用[4]提到Matlab的实现方法,这些都需要准确标注。</think>### 最小生成树算法详解(数学建模方向) #### 一、核心概念与算法原理 1. **最小生成树(Minimum Spanning Tree, MST)定义** 给定带权无向连通图$G=(V,E)$,其生成树是包含所有顶点且边权总和最小的树形结构,具有$|V|-1$条边且无环。 2. **Prim算法原理** 通过维护两个集合$P$(已选顶点)和$V-P$(未选顶点),每次选择连接两集合的最小权重边加入生成树,直到所有顶点被包含[^3]。 **时间复杂度**:$O(n^2)$(邻接矩阵实现),适合稠密图。 3. **Kruskal算法原理** 按边权重升序排序,依次选择不构成环的边加入生成树,直到选满$n-1$条边。通过并查集数据结构高效判断环路[^2]。 **时间复杂度**:$O(m \log m)$(边排序耗时),适合稀疏图。 #### 二、代码实现对比 1. **Python实现Prim算法** ```python import heapq def prim(graph): visited = set() heap = [(0, 0, None)] # (weight, node, parent) mst = [] while heap: weight, u, parent = heapq.heappop(heap) if u not in visited: visited.add(u) if parent is not None: mst.append((parent, u, weight)) for v, w in graph[u]: if v not in visited: heapq.heappush(heap, (w, v, u)) return mst ``` 2. **Matlab实现Kruskal算法**(基于引用[4]) ```matlab function mst = kruskal(adjMatrix) [n, ~] = size(adjMatrix); edges = []; for i = 1:n for j = i+1:n if adjMatrix(i,j) > 0 edges = [edges; i j adjMatrix(i,j)]; end end end edges = sortrows(edges, 3); % 按权重排序 parent = 1:n; mst = []; for k = 1:size(edges,1) u = edges(k,1); v = edges(k,2); if find(parent, u) ~= find(parent, v) mst = [mst; edges(k,:)]; parent = union(parent, u, v); end end end ``` #### 三、数学建模应用场景 1. **通信网络建设** 设计光纤网络时,要求连接所有城市且总成本最低,可转化为MST问题。 2. **交通规划** 在高速公路网中寻找连接所有城市的最经济路线(边权=建设成本)。 3. **电路板布线** 连接个电子元件时,用最小总长度的导线完成互连。 #### 四、学习资料推荐 1. **教材与论文** - 《算法导论》第23章 最小生成树 - 数学建模竞赛优秀论文(中国知网可查历赛题优秀解法) 2. **在线资源** - OI Wiki图论专题(含动态演示) - Coursera普林斯顿大学《Algorithms, Part II》Week 4 3. **实战题库** - LeetCode 1584. 连接所有点的最小费用(Kruskal实现) - HDU 1233 还是畅通工程(Prim算法模板题) #### 五、比赛注意事项 1. **数据规模与算法选择** - 顶点数$n>5000$时优先使用Kruskal(稀疏图) - 需要频繁查询顶点状态时选择Prim(稠密图) 2. **验证正确性方法** - 交叉验证:分别用Prim和Kruskal计算结果是否一致 - 数学归纳法证明边选择策略的最优性[^2] 3. **模型扩展方向** - 带约束条件的MST(如顶点度数限制) - 动态MST(边权随时间变化)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值