无向连通网的最小生成树算法[第3部分]

普利姆算法的测试数据如下:每行数据表示边的两个端点和权值
10 13
1 0 4
2 1 2
3 0 3
4 3 8
5 1 2
5 2 2
5 4 1
6 3 10
7 4 4
8 5 4
8 7 6
9 6 5
9 7 2

普利姆最小生成树算法:

/*
    时间:2017.1.1
    描述:普利姆算法求解最小生成树
*/
#include<iostream>
#include<climits>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<fstream>
#define INF INT_MAX
#define FILEINPUT 1
using namespace std;

typedef struct edgeNode
{
    int from,to;
    int cost;
}
EDGENODE;

void creatMatrix(int **AdjMatrix,int n,int e);                              //构建无向图的邻接矩阵
void printMatrix(int **AdjMatrix,int n);                                    //输出图的邻接矩阵
void initEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int start);        //初始化边集
int  chooseEdge(EDGENODE *edgeSet,int n,int index);                         //从候选边集中选取权重最小的边
void modfiyEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int index,int to);//调整候选边集
void primMst(int **AdjMatrix,EDGENODE *edgeSet,int n,int start);            //普利姆算法
void printMst(EDGENODE *edgeSet,int n);                                     //输出最小生成树选举结果

int main()
{
    //freopen("data.txt","r",stdin);
    #if FILEINPUT                                           //条件编译:输入重定向到文件(输入邻接矩阵数据)
        ifstream fin("data.txt");
        streambuf *strm_buf=cin.rdbuf();
        cin.rdbuf(fin.rdbuf());
    #endif

    int i,n,e,start;
    int **AdjMatrix;                                        //存储邻接矩阵
    EDGENODE *edgeSet;                                      //存储最小生成树选的边集
    cout<<"Enter the number of nodes and edges:"<<endl;
    cin>>n>>e;

    AdjMatrix=(int **)malloc(sizeof(int *)*n);              //为邻接矩阵分配存储空间
    for(i=0;i<n;i++)
        AdjMatrix[i]=(int *)malloc(sizeof(int)*n);

    edgeSet=(EDGENODE *)malloc(sizeof(EDGENODE)*n);         //为最小生成树边集合配存储空间

    creatMatrix(AdjMatrix,n,e);                             //构建无向图的邻接矩阵
    printMatrix(AdjMatrix,n);                               //输出图的邻接矩阵

    #if FILEINPUT                                           //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点)
        cin.rdbuf(strm_buf);
    #endif

    while(1)
    {
        cout<<"Enter the start position of the Graph: ";
        cin>>start;
        primMst(AdjMatrix,edgeSet,n,start);
        printMst(edgeSet,n);
    }

    #if FILEINPUT                                           //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点)
        fin.close();
    #endif

    return 0;
}

void creatMatrix(int **AdjMatrix,int n,int e)
{
    int i,j,from,to,cost;
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            AdjMatrix[i][j]=INF;
    cout<<"<from----to----cost>"<<endl;
    for(i=0;i<e;i++)
    {
        cin>>from>>to>>cost;
        AdjMatrix[from][to]=cost;
        AdjMatrix[to][from]=cost;
    }
}

void printMatrix(int **AdjMatrix,int n)
{
    int i,j;
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)
            if(AdjMatrix[i][j]==INF)
                cout<<setiosflags(ios::left)<<setw(6)<<"INF";
            else
                cout<<setiosflags(ios::left)<<setw(6)<<AdjMatrix[i][j];
        cout<<endl;
    }
}

void initEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int start)
{
    int i,index=0;
    for(i=0;i<n;i++)
        if(i!=start)
        {
            edgeSet[index].from=start;
            edgeSet[index].to=i;
            edgeSet[index].cost=AdjMatrix[start][i];
            index++;
        }
}

int chooseEdge(EDGENODE *edgeSet,int n,int index)
{
    int minCost=INF,minPos,i;
    for(i=index;i<n-1;i++)
        if(edgeSet[i].cost<minCost)
        {
            minCost=edgeSet[i].cost;
            minPos=i;
        }
    if(minCost==INF)
    {
        cout<<"The Graph is disconnected!"<<endl;
        exit(1);//图不连通,程序结束
    }
    return minPos;
}

void modfiyEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int index,int to)
{
    int i,cost;
    for(i=index;i<n-1;i++)
    {
        cost=AdjMatrix[to][edgeSet[i].to];
        if(cost<edgeSet[i].cost)
        {
            edgeSet[i].cost=cost;
            edgeSet[i].from=to;
        }
    }
}

void primMst(int **AdjMatrix,EDGENODE *edgeSet,int n,int start)
{
    int iter,minPos,to;
    EDGENODE edge;
    initEdgeSet(AdjMatrix,edgeSet,n,start);     //初始化边集合
    for(iter=0;iter<n-1;iter++)
    {
        minPos=chooseEdge(edgeSet,n,iter);      //从边集中选择取值最小边
        edge=edgeSet[minPos];                   //将选择的最小边edgeSet[iter]
        edgeSet[minPos]=edgeSet[iter];          
        edgeSet[iter]=edge;
        to=edgeSet[iter].to;                    //将选择的边结点加入U集合
        modfiyEdgeSet(AdjMatrix,edgeSet,n,iter,to);//调整候选边结点
    }
}

void printMst(EDGENODE *edgeSet,int n)
{
    int index;
    int totalCost=0;
    for(index=0;index<n-1;index++)
    {
        cout<<"("<<edgeSet[index].from<<","<<edgeSet[index].to<<") "<<edgeSet[index].cost<<endl;
        totalCost+=edgeSet[index].cost;
    }
    cout<<"totalCost: "<<totalCost<<endl;
}
克鲁斯科尔算法的测试数据:第一行表示图的顶点数和边数;从第二行开始表示表的顶点编号和权值
10 13
0 1 4
1 2 2
0 3 3
3 4 8
1 5 2
2 5 2
4 5 1
3 6 10
4 7 4
5 8 4
7 8 6
6 9 5
7 9 2

克鲁萨卡尔算法:

/*
    时间:2017.1.1
    描述:结合并查集实现克鲁斯卡尔算法求最小生成树
*/
#include<iostream>
#include<climits>
#include<iomanip>
#include<cstring>
#include<fstream>
#include<algorithm>
#define INF INT_MAX
#define FILEINPUT 1
using namespace std;

typedef struct edgeNode
{
    int from,to;
    int cost;
}
EDGENODE;

bool operator<(const EDGENODE &a,const EDGENODE &b)
{
    if(a.cost!=b.cost)
        return a.cost<b.cost;
    else if(a.from!=b.from)
        return a.from<b.from;
    else 
        return a.to<b.to;
}

int flag[512];

void creatMatrix(int **AdjMatrix,EDGENODE *edgeSet,int n,int e);
void printMatrix(int **AdjMatrix,int n);
void printEdgeSet(EDGENODE *edgeSet,int e);
void kruskalMst(EDGENODE *edgeSet,int n,int e);
int findRootEdge(int nodeNumber);
int mergeEdge(int nodeFrom,int nodeTo);

int main()
{
    //freopen("data.txt","r",stdin);
    #if FILEINPUT                                           //条件编译:输入重定向到文件(输入邻接矩阵数据)
        ifstream fin("data.txt");
        streambuf *strm_buf=cin.rdbuf();
        cin.rdbuf(fin.rdbuf());
    #endif

    int i,n,e;
    int **AdjMatrix;                                        //存储邻接矩阵
    EDGENODE *edgeSet;                                      //边集合

    cout<<"Enter the number of nodes and edges:"<<endl;     
    cin>>n>>e;

    AdjMatrix=(int **)malloc(sizeof(int *)*n);              //为邻接矩阵分配存储空间
    for(i=0;i<n;i++)
        AdjMatrix[i]=(int *)malloc(sizeof(int)*n);

    edgeSet=(EDGENODE *)malloc(sizeof(EDGENODE)*e);         //为边集合分配存储空间

    for(i=0;i<n;i++)                                        //初始化并查集
        flag[i]=i;

    creatMatrix(AdjMatrix,edgeSet,n,e);
    printMatrix(AdjMatrix,n);

    kruskalMst(edgeSet,n,e);

    #if FILEINPUT                                           //条件编译:输入重定向到键盘(输入普利姆算法的起始顶点)
        cin.rdbuf(strm_buf);
        fin.close();
    #endif

    return 0;
}

void creatMatrix(int **AdjMatrix,EDGENODE *edgeSet,int n,int e)
{
    int i,j,from,to,cost;
    EDGENODE edge;
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            AdjMatrix[i][j]=INF;
    cout<<"<from----to----cost>"<<endl;
    for(i=0;i<e;i++)
    {
        cin>>from>>to>>cost;
        AdjMatrix[from][to]=cost;
        AdjMatrix[to][from]=cost;
        edge.from=from;
        edge.to=to;
        edge.cost=cost;
        edgeSet[i]=edge;
    }
}

void printMatrix(int **AdjMatrix,int n)
{
    int i,j;
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)
        {
            if(AdjMatrix[i][j]==INF)
                cout<<setiosflags(ios::left)<<setw(6)<<"INF";
            else
                cout<<setiosflags(ios::left)<<setw(6)<<AdjMatrix[i][j];
        }
        cout<<endl;
    }
}

void printEdgeSet(EDGENODE *edgeSet,int e)
{
    int index=0;
    for(index=0;index<e;index++)
        cout<<"("<<edgeSet[index].from<<","<<edgeSet[index].to<<") "<<edgeSet[index].cost<<endl;
}

int findRootEdge(int nodeNumber) 
{
    int i,j,root;
    root=nodeNumber;
    while (flag[root]!=root)                //循环结束,则找到同一边集中的最小结点编号
          root= flag[root];       
    i=nodeNumber;
    while(i!=root)                          //本循环修改查找路径中所有边结点编号
    {
        j=flag[i];
        flag[i]=root;
        i=j;
    }
    return root;
}

int mergeEdge(int nodeFrom,int nodeTo)      //边结点合并到连通图中
{
    int indexFrom=findRootEdge(nodeFrom);
    int indexTo=findRootEdge(nodeTo);

    if(flag[indexFrom]<flag[indexTo])
       flag[indexTo]=indexFrom;
    else
       flag[indexFrom]=indexTo;

    if(indexFrom==indexTo)
        return 1;
    else
        return 0;
}

void kruskalMst(EDGENODE *edgeSet,int n,int e)
{
    int index=0;
    int countEdge=0;
    int minCost=0;
    //cout<<"------------------------------------"<<endl;
    //printEdgeSet(edgeSet,e);
    sort(edgeSet,edgeSet+e);                            //对边集进行快速排序
    //cout<<"------------------------------------"<<endl;
    //printEdgeSet(edgeSet,e);
    //cout<<"------------------------------------"<<endl;
    while(index<e)
    {
        int from=edgeSet[index].from;
        int to=edgeSet[index].to;
        int cost=edgeSet[index].cost;
        if(mergeEdge(from,to)==0)                       //利用并查集判断环路,同时对查找路径进行压缩合并
        {
            countEdge++;
            minCost+=cost;
            cout<<"("<<from<<","<<to<<") "<<cost<<endl;
            index++;
        }
        else
        {
            index++;
        }
        if(countEdge==n-1)
        {
            break;
        }
    }
    if(index<e)                                             
        cout<<"minCost: "<<minCost<<endl;
    else
    {
        cout<<"The Graph is disconnected!"<<endl;       //index>=e则不能构造最小生成树
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值