最小生成树问题

来源:互联网 发布:php curl urlencode 编辑:程序博客网 时间:2024/06/05 20:18

假设要在n个城市之间建立通信网,则联通n个城市只需要n-1条线路,这是,自然会考虑如何在最节省经费的前提下建立这个通信网,这就是经典的最小生成树问题。

构造最小生成树有多种算法,多数利用最小生成树的MST性质,此处以普里姆算法为例。


MST性质:

                    N={V, {E}}是连通网, V顶点集合, E边的集合,

                    TE是N上最小生成树中边的集合

                    从U = {u0} (U0属于V),TE = { } 开始,重复执行下列错做:

                    在所有u属于V,v属于V-U的边(u, v)属于E中找一条代价最小的边(u0, v0)并入集合TE ,同时v0并入U,直至U=V为止,此时TE中必有n-1条边,则T = {U, {TE}}为最小生成树。


此处以数组法表示的无向网构造最小生成树,用邻接表示法表示的网算法与此类似。

首先构造一个无向网,再用该无向网从第0个顶点出发构造一棵最小生成树。


无向网G



构造后的最小生成树



#include <stdio.h>#define MAX 20 //最大顶点数typedef struct ArcCell //无向网中的弧{    int adj; //弧的权值}ArcCell, AdjMatrix[MAX][MAX];typedef struct MGraph //数组表示法表示图{    char vexs[MAX]; //顶点值    AdjMatrix arcs; //临接矩阵    int vexnum; //顶点数    int arcnum; //弧数}MGraph;typedef struct Arc //生成树中的弧{    int fir; //生成树中表示弧的第一个顶点    int sec; //生成树中表示弧的第二个顶点    int weight; //弧的权值}Arc;typedef struct Vex //生成树中的顶点{    char value; //存放顶点值}Vex;typedef struct MiniTree //最小生成树{    Arc arcs[MAX]; //弧    Vex vexs[MAX]; //顶点    int vexnum; //顶点数    int arcnum; //弧数}MiniTree;typedef enum Bool{FALSE, TRUE} Bool;typedef struct Temp  //辅助结构{    int pos; //存放顶点编号    int lowcost; //存放最小值    Bool visited; //访问标志}Temp;//确定输入的顶点值在无向网中的位置int LocateVex(MGraph **G, char c){    int i;    for(i=0; i<(*G)->vexnum; i++)    {        if((*G)->vexs[i] == c)    return i;    }    return -1;}//数组表示法构造无向网void CreateUDN(MGraph *G){    int i, j, k;        printf("Input vexnum and arcnum:\n"); //提示输入顶点数和弧数    scanf("%d", &(G->vexnum));getchar();    scanf("%d", &(G->arcnum));getchar();        printf("Input vex's value:\n"); //输入顶点值    for(i=0; i<G->vexnum; i++)    {        scanf("%c", &(G->vexs[i]));getchar();    }        for(i=0; i<G->vexnum; i++) //初始化临接矩阵    {        for(j=0; j<G->vexnum; j++)    G->arcs[i][j].adj = 0;    }    printf("Input %d arc\n", G->arcnum);    for(k=0; k<G->arcnum; k++)    {        char v1, v2; //两个顶点值int w; //两个顶点间的权值scanf("%c %c %d", &v1, &v2, &w);getchar();i = LocateVex(&G,v1);j = LocateVex(&G,v2);G->arcs[i][j].adj = G->arcs[j][i].adj = w;    }}//选出辅助数组中未访问的非0最小值int selectMin(Temp *temp, MiniTree **mt){    //找到第一个不为0的元素,设为最小值    int i, min;    for(i=0; i<(*mt)->vexnum; i++)    {        if(temp[i].lowcost != 0 && temp[i].visited == FALSE)    break;    }    min = i;    for(i=0; i<(*mt)->vexnum; i++)    {        if(temp[i].lowcost !=0 && temp[i].visited == FALSE){    if(temp[min].lowcost > temp[i].lowcost)        min = i;}    }    return min;}//以无向网为例,从第u个顶点出发,构造最小生成树void CreateMiniTree(MGraph *G, int u, MiniTree *mt){        int i, j, k;    Temp temp[MAX];    mt->vexnum = G->vexnum;    mt->arcnum = mt->vexnum - 1;    for(i=0; i<G->vexnum; i++) //辅助数组初始化     {        if(i != u){    Temp t = {u, G->arcs[u][i].adj, FALSE};    temp[i] = t;}    }    Temp t = {u, 0, TRUE};    temp[u] = t;    for(i=1; i<G->vexnum; i++)    {        k = selectMin(temp, &mt);mt->arcs[i-1].fir = temp[k].pos;mt->arcs[i-1].sec = k;mt->arcs[i-1].weight = temp[k].lowcost;temp[k].lowcost = 0; //第k个顶点并入Utemp[k].visited = TRUE;//开始调整下一行,保留存在路径的较小值及顶点值,保留之前lowcost为0后来存在路径的新值及顶点值for(j=0; j<G->vexnum; j++){    if(temp[j].visited == FALSE)    {        if(temp[j].lowcost != 0){    if(G->arcs[k][j].adj < temp[j].lowcost &&       G->arcs[k][j].adj != 0)    {        Temp t = {k, G->arcs[k][j].adj, FALSE};temp[j] = t;    }}else{    if(G->arcs[k][j].adj != 0)    {        Temp t = {k, G->arcs[k][j].adj, FALSE};temp[j] = t;    }}    }}    }}int main(){    int i, j, k;    MGraph G;    MiniTree mt;    CreateUDN(&G); //构造无向网G        for(i=0; i<G.vexnum; i++) //测试顶点值    {        printf("%c ", G.vexs[i]);    }    printf("\n");    for(i=0; i<G.vexnum; i++) //测试临接矩阵    {        for(j=0; j<G.vexnum; j++){    printf("%d ", G.arcs[i][j].adj);}printf("\n");    }    CreateMiniTree(&G, 0, &mt); //从第0个元素(v1)开始构造最小生成树    for(i=0; i<mt.arcnum; i++) //输出构造的最小生成树的各个弧以及权值    {        char fir = G.vexs[mt.arcs[i].fir];char sec = G.vexs[mt.arcs[i].sec];        int weight = mt.arcs[i].weight;printf("%c %c %d\n", fir, sec, weight);    }    printf("test\n");    return 0;}


测试数据


输入G的顶点数和边数



输入G的顶点值,此处以1代表v1,2代表v2,以此类推



输入表示弧的两个顶点的编号以及弧的权值



显示构造的无向网G的各个顶点值 ,此处以1代表v1,2代表v2,以此类推



显示构造的无向网G的邻接矩阵



输出构成最小生成数的弧以及权值,

 分别对应为 (v1, v3, 1)

                      (v3, v6,  4)

                      (v6, v4, 2)

                      (v3, v2, 5)

                      (v2, v5, 3)


0 0
原创粉丝点击