OJ 1428 最小生成树

OJ 1428. Minimum Spanning Tree

题目描述

给定一张 n个点,m条边的有权无向连通图,求最小生成树的边权和。

Input

请从 stdin 读入。
输入第一行为两个正整数 n , m n, m n,m ( 1 ≤ n ≤ 5000 , 1 ≤ m ≤ 2 × 1 0 5 ) (1≤n≤5000,1≤m≤2×10^5) (1n5000,1m2×105)
接下来 m 行,第 i 行为用空格隔开的整数 u i u_i ui, v i v_i vi, w i w_i wi ( 1 ≤ u i , v i ≤ n , 1 ≤ w i ≤ 10000 1 \leq u_i, v_i \leq n, 1 \leq w_i \leq 10000 1ui,vin,1wi10000),表示第 i条边为从 u i u_i ui v i v_i vi
输入可能存在重边与自环。

Output

请输出到 stdout 中。
输出一行,包含一个整数,表示你的答案。

Sample Input

4 4
1 2 1
2 3 2
3 4 3
4 1 4

3 3
1 2 3
2 3 1
3 1 2

Sample Output

6
3

Constraints

Time Limit: 1s
Memory Limit: 128MB

Solution

  采用无优化的 Prim算法求解最小生成树。无优化刚好能过,时间复杂度O( ∣ V ∣ 2 + ∣ E ∣ |V|^2+|E| V2+E)。
  进一步可以采用heap优化,时间复杂度O[ ( ∣ V ∣ + ∣ E ∣ ) log ⁡ ∣ V ∣ (|V|+|E|)\log|V| (V+E)logV]。如果采用Fabonacci heap优化,时间复杂度为O ( ∣ E ∣ + ∣ V ∣ log ⁡ ∣ V ∣ ) (|E|+|V|\log|V|) (E+VlogV)

Code

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

struct edge{
    int to;
    int weight;
    edge(int v, int w){
        to=v;
        weight=w;
    }
};

vector<bool> visited;
vector<int> cost;
vector<vector<edge>> g;

int prim(){
    int ans=0;
    visited[1]=true;
    cost[1]=0;
    for(int i=0;i<g[1].size();i++){
        int v=g[1][i].to;
        cost[v]=g[1][i].weight;
    }
    bool flag=true;
    while(flag){
        flag=false;
        int min_cost=100000;
        int min_index=1;
        for(int i=1;i<cost.size();i++){
            if(visited[i]){
                continue;
            }
            if(cost[i]<min_cost){
                flag=true;
                min_cost=cost[i];
                min_index=i;
            }
        }
        if(flag){
            visited[min_index]=true;
            ans+=min_cost;
            for(int i=0;i<g[min_index].size();i++){
                int v=g[min_index][i].to;
                if(!visited[v]){
                    cost[v]=min(cost[v],g[min_index][i].weight);
                }
            }
        }
    }
    return ans;
}

int main()
{
    int n, m;
    cin>>n>>m;
    visited.assign(n+1,false);
    g.assign(n+1,vector<edge>());
    cost.assign(n+1,100000000);
    int u, v, w;
    for(int i=0;i<m;i++){
        cin>>u>>v>>w;
        if(u==v){
            continue;
        }
        else{//重边选小的
            bool flag1 = false;
            for(int i=0;i<g[u].size();i++){
                if(g[u][i].to==v){
                    if(g[u][i].weight>w){
                        g[u][i].weight=w;
                    }
                    flag1 = true;
                    break;
                }
            }
            if(flag1==false){
                edge e1(v,w);
                g[u].push_back(e1);
            }
            bool flag2 = false;
            for(int i=0;i<g[v].size();i++){
                if(g[v][i].to==u){
                    if(g[v][i].weight>w){
                        g[v][i].weight=w;
                    }
                    flag2 = true;
                    break;
                }
            }
            if(flag2==false){
                edge e2(u,w);
                g[v].push_back(e2);
            }
        }
    }
    cout<<prim();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值