求最小生成树两种常用算法(Prim,Kruskal)

Prim求最小生成树

思路:和djstl算法求最短路径类似,都是进行n次循环,每次找到dist最小的点,然后更新其他点.但是有两点不同:

  1. 找到最小点t后,要判断dist[t]是否是无穷,如果是无穷,说明没有最小生成树
  2. sum+=dist[t];
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;

typedef long long ll;
typedef pair<int, int> pii;


int e[N*2],ne[N*2],h[N];
int w[N];
int dist[N];
int st[N];
int idx = 0;
int n,m;
void add(int a,int b,int c)
{
    e[idx]  = b;
    w[idx] = c;
    ne[idx] = h[a];
    h[a] = idx++;
}
void prim()
{
    dist[1] = 0;
    int sum = 0;
  for(int i  =0;i<n;i++)
  {
      int t = -1;
      for(int k = 1;k<=n;k++)
      {
          if(st[k])continue;
      if(t==-1||(dist[k]<dist[t]))
      {
          t  =k;
      }
      }
      if(dist[t]==0x3f3f3f3f)
      {
          cout<<"impossible";
          return ;
      }
      
      sum+=dist[t];
      st[t] =1;
      for(int j =h[t];j!=-1;j = ne[j])
      {
          int k = e[j];
          dist[k] = min(dist[k],w[j]);
      }
  }
  
  
 
  cout<<sum;
  return ;
  
}
int main()
{
    
    cin>>n>>m;
    memset(h,-1,sizeof(h));
    memset(dist,0x3f,sizeof(dist));
    memset(w,0x3f,sizeof(w));
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
        
    }
    prim();
    
}

Kruskal(核心思想:并查集)

思路: 用结构体将所有边存下来,并且把边按照从小到大的顺序排列,用变量cnt记录最小生成树的边数
再遍历所有的边,如果边上的两个点都在一个集合里面,就不加入最小生成树,反之就加入,
更新集合,生成树,边数
遍历完之后,如果最下生成树的边数小于n-1,就代表没有最小生成树

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;

typedef long long ll;
typedef pair<int, int> pii;

int p[N];
int n, m;

struct edge
{
    int a,b,w;
    bool operator <(const edge&W)const
    {
        return w<W.w;
    }
    
}e[N*2];

int find(int a)
{
     if(p[a]!=a) 
     p[a] = find(p[a]);
     return p[a];
}
void klusker()
{
    sort(e,e+m);
    for(int i =1;i<=n;i++)
    p[i] = i;
    int sum = 0;
    int cnt = 0;
    for(int i  =0;i<m;i++)
    {
        int a = e[i].a;
        int b = e[i].b;
        int w = e[i].w;
        int x = find(a);
        int y  = find(b);
        if(x!=y)
        {
            sum+=w;
            p[x] = y;
            cnt++;
        }
    }
    if(cnt<n-1)
    {
      
        cout<<"impossible";
    }
    else 
    cout<<sum;
}

int main()
{
 cin>>n>>m;
 
 for(int i = 0;i<m;i++)
 {
     int a,b,c;
     cin>>a>>b>>c;
     e[i] = {a,b,c};
 }
 
 klusker();
 return 0;
 
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值