最小生成树的prim和Kruskal算法

最小生成树

用最小的代价将图中的每一个点联通

我们有两种基于贪心策略的算法

Prim

  1. 初始化一点作为根节点

  2. 选择权值最小的与当前联通块相连的点加入到联通块中

  3. 如果图未遍历完成 则返回2

Kruskal

  1. 初始化图中所以的边 并按权值进行排序

  2. 遍历边的数组 如果当前边所连两点不连通 则将其连接

Prim代码

#include<bits/stdc++.h> 

using namespace std;

const int maxn = 5050;
const int maxm = 200020;
int n,m;
struct Edge{
    int from;
    int to;
    ll cost;
}edge[maxm];
bool cmp(Edge a,Edge b)
{
    return a.cost<b.cost;
}
int fath[maxn]; //我们用并查集来维护当前两个点是否联通

void init()
{
    for(int i=0;i<maxn;++i) 
        fath[i] = i;
}
int find(int f)
{
    if(f==fath[f])  return f;
    return fath[f] = find(fath[f]);
}

void unionSet(int a,int b)
{
    int u = find(a), v = find(b);
    if(u==v)    return ;
    fath[u] = v;
}
long long Kruskal()
{
    long long ans = 0;
    for(int i=1;i<=m;++i)
    {
        if(find(edge[i].from)==find(edge[i].to))    continue;//如果联通,则跳过当前边
        unionSet(edge[i].from,edge[i].to);  //两个点的集合合并
        ans+=edge[i].cost;
    }
    return ans;
}
int main()
{
    cin >> n >> m;
    for(int i=1;i<=m;++i)
    {
        cin>>edge[i].from >> edge[i].to>>edge[i].cost; 
    }
    init();
    sort(edge+1,edge+1+m,cmp);
    ll ans = Kruskal();

    for(int i=1;i<=n;++i)
    {
        if(find(i)!=find(1))    ans = -1;
    }//检查是否所以的点都联通
    if(ans==-1) cout << "orz" << endl;
    else cout << ans<<endl;
    return 0;
}

Kruskal代码


#include<bits/stdc++.h> 

using namespace std;

const int maxn = 5050;
const int maxm = 200020;
int n,m;

struct edge{
   int to;
   ll cost;
   edge(int tt,ll cc):to(tt),cost(cc){ }
   edge(){}
   bool operator<(const edge &a)const{ //维护小根堆
       return a.cost<cost;
   }
};

bool vis[maxn];                     //记录点是否加入
priority_queue<edge> que;       
vector<edge>        G[maxn];        //记录所有的边
   
ll prim()
{
   ll ans = 0;
   vis[1] = 1;         //初始化 将1号点作为初始点
   for(int i=0;i<G[1].size();++i)      //将所有的边加入堆中
       que.push(G[1][i]);
   while(que.size())           
   {
       edge e = que.top(); //获得当前最小的边
       que.pop();
       if(vis[e.to])   continue;   //如果加入则挑过
       vis[e.to] = 1;
       ans += e.cost;
       for(int i=0;i<G[e.to].size();++i)   //将当前点所有的边加入堆中
           que.push(G[e.to][i]); 
   }
   return ans;
}
int main()
{
   cin >> n >> m;
   for(int i=0;i<=n;++i)
       G[i].clear();
   while(que.size())   que.pop();
   for(int i=1;i<=m;++i)
   {
       int u,v;
       ll cost;
       cin >> u >> v >>cost;
       G[u].push_back(edge(v,cost));//无向图 两个点都要加入
       G[v].push_back(edge(u,cost));
   }
   ll ans = prim();
   for(int i=1;i<=n;++i)
   {
       if(!vis[i]) ans = -1;
   }
   if(ans==-1) cout << "orz" <<endl;
   else        cout << ans<<endl;
   return 0;

} 

转载于:https://www.cnblogs.com/xxrlz/p/10487032.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值