最小生成树

1,Kueskal(加边)

就是一个并查集的应用吧

先把所有的边按从小到大排序,然后再按顺序判断每一条边要不要加上,就是边两边的点已经是一个集合(就是说,已经有可以联通的路了)就不用再加了,还不是就加

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 1000000 + 10;
int fa[maxn];
struct edge{
  int u;
  int v;
  int len;
}e[maxn];
bool cmp(edge a, edge b){
    return a.len < b.len;
}
int init(){
  for(int i = 0; i < maxn; i++){
    fa[i] =  i;
  }
}
/*int tofind(int x){
  int an = x;
  if(an == fa[an]) return an;
  return fa[an] = tofind(an);
}*/
int tofind(int x){
    int an = x;
    while(fa[an] != an){
        an = fa[an];
    }//找根节点
    int t = x;
    while(fa[x] != an){
        x = fa[x];
        fa[t] = an;
        t = x;
    }//缩短路径
    return an;
}
int tojoin(int a, int b){
  a = tofind(a);
  b = tofind(b);
  if(a != b){
    fa[a] = b;
    return 1;
  }
  return 0;
}//合并
int main(){
 int n;
 while(cin>>n){
    for(int i = 0; i < n; i++){
        scanf("%d%d%d",e[i].u, e[i].v, e[i].len);
    }
    sort(e, e + n, cmp);
    int sum = 0;
    for(int i = 0; i < n; i++){
        sum += e[i].len*tojoin(e[i].u, e[i].v);
    }
    printf("%d",sum);
 }
 return 0;
}
2.Prim(加点)

从第一个点开始,找这一点连着的所有的边里最短的,然后再从这个边连着的那个点开始遍历(如果有环的话只能用这个方法)

代码(鹏哥的代码/[无辜])

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 20000 + 10;
int cnt = 0;
struct edge{
    int v;
    int len;
    int nex;
    bool operator <(const edge &a) const{
        return len > a.len;//重载运算符,有点酷
    }
}e[maxn];
int id[maxn];
bool used[maxn];
void add(int from, int to, int len){
  e[cnt].v = to;
  e[cnt].len = len;
  e[cnt].nex = id[from];
  id[from] = cnt++;
}//链式前向星
void init(int n){
    cnt = 0;
    for(int i = 0; i < n; i++){
        id[i] = -1;
    }
    memset(e, 0, sizeof(e));
    memset(used, 0, sizeof(used));
}
int Prime(int x, int n){
    int tot = 1;
    int TT = 0;
    int sum = 0;
    priority_queue<edge> q;//因为重载了运算符所以这里的优先队列是从小到大排的
    for(;tot < n;)
    {
        used[x] = 1;//标记点
        for(int i = id[x]; ~i; i = e[i].nex){
            if(used[e[i].v])
            continue;
            q.push(e[i]);
        }
        while(!q.empty()){
            edge mye = q.top();
            q.pop();
            if(used[mye.v])
                continue;
            else{
                sum += mye.len;
                x = mye.v;
                tot++;
                break;
            }
        }
    }
    while(!q.empty()){q.pop();}
    return sum;
}
int main(){
    int n, m;
    while(scanf("%d %d", &m, &n), m){
        int a, b, c;
        init(n);
        for(int i = 0; i < m; i++){
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c);
            add(b, a, c);
        }
        //for(int i=0;i<cnt;i++)
        //   cout<<e[i].len<<' '<<e[i].nex<<' '<<e[i].v<<endl;
        //for(int i=1;i<=14;i++)
        //  cout<<id[i]<<' ';
        //cout<<endl;
        int ans = Prime(1, n);
            printf("%d\n", ans);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值