最小生成树

prim算法

对这种有记忆性质的变量(在外面定义,循环时会记录上次的值,类似于全局变量),每次使用都要小心,注意初始化问题!!!


#include <iostream>

using namespace std;
const int N = 6;
/*int e[N][N]={
        {0,6,1,5,9999,9999},
        {6,0,5,9999,3,9999},
        {1,5,0,5,6,4},
        {5,9999,5,0,9999,2},
        {9999,3,6,9999,0,6},
        {9999,9999,4,2,6,0}
}*///图,注意此图是无向图,关于对角线对称的。
int e[N][N]={
        {9999,6,1,5,9999,9999},
        {6,9999,5,9999,3,9999},
        {1,5,9999,5,6,4},
        {5,9999,5,9999,9999,2},
        {9999,3,6,9999,9999,6},
        {9999,9999,4,2,6,9999}
};//图,注意此图是无向图,关于对角线对称的。

int dist[N];//各点距离生成树的距离
int book[N] = {0};//标记各节点是否选入生成树;
int sum = 0;
int prim(){
    for (int i = 0; i < N; ++i) {
       dist[i] = e[0][i];
    }
    book[0] = 1;
    int tmp;
    int minIndex;
    for (int l = 0; l < N-1; ++l) {
        tmp = 99999;//第一次忘了在此处初始化tmp, tmp会记录上次运算的值,不初始化有可能在下面的循环里得不到更新minIndex的值,因此此处需要初始化。
        // TODO对这种有记忆性质的变量(在外面定义,循环时会记录上次的值,类似于全局变量),每次使用都要小心,注意初始化问题!!!
        for (int j = 0; j < N; ++j) {
            if (tmp > dist[j] && !book[j]) {
                tmp = dist[j];
                minIndex = j;
            }
        }
        book[minIndex] = 1;
        sum += dist[minIndex];
        for (int k = 0; k < N; ++k) {
            if(!book[k]) {
//                cout << dist[4] <<" " << e[1][4] <<endl;//开始的时候输入数组输错了,浪费了很多时间,以后拍错先看输入是否正确,然后考虑边界,然后考虑逻辑
                if (dist[k] > e[minIndex][k]) dist[k] = e[minIndex][k];
            }
        }
    }
    return sum;
}
int main() {
    cout << prim() << endl;
    return 0;
}

kruskal算法

考虑清楚用并查集的意义何在!!!


#include <iostream>
#include <queue>
using namespace std;

/*
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
*/

int sum = 0;
//并查集
int par[8];//一共6个顶点,第七个顶点是未加入树里,第0个顶点是加入树里的 //第一次这种设计是错的,其实只要par[6]就够了,是判断下一条边加进来会不会成环路,而不是把所有点加进树就行了(有可能不连通)
void initSet(){
    for (int i = 0; i < 8; ++i) {
        par[i] = i;
    }
}
int getPar(int a){
    if(par[a] != a){
        par[a] = getPar(par[a]);
    }
    return par[a];
}
void mergeSet(int a,int b){
    par[getPar(a)] = getPar(b);
}

struct Edge{
    int a,b;
    int w;
    Edge(){}
    Edge(int x,int y,int z):a(x),b(y),w(z){}
    friend bool operator < (Edge m,Edge n){//从小到大排列!!!
        return m.w > n.w;
    }
};
Edge edge[9];//一共9条边

priority_queue <Edge> q;

int main() {
    int m,n,a,b,c;
    Edge tmpEdge;
    cin >> m >> n;
    while (n--){
        cin >> tmpEdge.a >> tmpEdge.b >> tmpEdge.w;
        q.push(tmpEdge);
    }
//    cout << q.top().w << endl;
    initSet();
    /*for (int i = 1; i < 8; ++i) {
        par[i] = 7;
    }*/ //设计错误!
    while (!q.empty()){
        tmpEdge = q.top();
        q.pop();
        if(getPar(tmpEdge.a) != getPar(tmpEdge.b)) {
//            mergeSet(tmpEdge.a,0);//此处错了,不是把所有点都放到树中就行了,而要判断所有点都要联通且没有环路!
//            mergeSet(tmpEdge.b,0);
            mergeSet(tmpEdge.a,tmpEdge.b);
            sum += tmpEdge.w;
        }
    }
    cout << sum << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值