【应用背景】连通图中各顶点所需要的最少成本。
(1)普里姆算法
1)根据需求构造返回类型,比如求最少成本,则定义返回类型为int型的函数,传入参数为邻接矩阵g,和出发点v0;
2)定义变量:lowcost[]数组(存储图中还未并入树的各顶点到当前生成树最短边的权值),vset[]数组(标记顶点是否被并入生成树中,1为真,0为假),循环变量i,j,整型变量min,k和sum,min表示生成树到剩余顶点最短边中最短的那条边的权值,k表示与这条边相连并将被并入生成树的顶点,sum表示成本总和;
3)做一个循环将lowcost数组初始化为与出发点相邻的各条边的权值,vset初始化为0;
4)将v0标记为1,表示生成树的根结点,接下来将剩余的n-1个顶点并入生成树中,即做n-1次循环:
5)返回sum,算法结束。
【算法分析】算法嵌套两层循环,外层循环执行n-1次,内层循环1中if语句比较n次,所以算法时间复杂度为。其中n为图中顶点个数,所以普里姆算法只与图的顶点数有关,顶点越少,时间复杂度越小,因此普里姆算法适合稠密图。
(2)核心代码:
int Prime(MGraph g, int v0)
{
int lowcost[maxSize], vset[maxSize],vpath[maxSize];
int i, j, k, min,sum = 0;
for (i = 0; i < g.n; ++i)
{
lowcost[i] = g.edges[v0][i];
vset[i] = 0;
if (lowcost[i] < INF)
vpath[i] = v0;
else
vpath[i] = -1;
}
vset[v0] = 1;
for (i = 0; i < g.n - 1; ++i)
{
min = INF;
for (j = 0; j < g.n; ++j)
if (vset[j] == 0 && lowcost[j] < min)
{
min = lowcost[j];
k = j;
}
sum += min;
vset[k] = 1;
printf("(%d,%d)", vpath[k], k);
for (j = 0; j < g.n; ++j)
if (vset[j] == 0 && g.edges[k][j] < lowcost[j])
{
lowcost[j] = g.edges[k][j];
vpath[j] = k;//父节点为K
}
}
return sum;
}
(3)验证算法正确性
数据来源:天勤树P193页例题
图样子:额,后期有时间更新
数据:
MGraph.txt
5
8
0 1 5
0 2 1
0 3 2
1 2 3
1 4 4
2 4 2
2 3 6
3 4 3
01234
测试代码:
#include
#include
#define maxSize 50
#define INF 65535
typedef struct
{
int num;
char info;
}VertexType;
typedef struct
{
int edges[maxSize][maxSize];
int n, e;//顶点数,和边数
VertexType vex[maxSize];//存放结点信息
}MGraph;
MGraph G;
int visit[maxSize];
FILE* fp;
void BuildGraph()
{
int i, j;
int v1, v2, w;
fp = fopen("C:\\CodeBlocksProject\\MGraph.txt", "r");
//Create Graph
fscanf(fp, "%d", &G.n);
for (i = 0; i < G.n; ++i)
for (j = 0; j < G.n; j++)
G.edges[i][j] = INF;//若为有向边则赋值为INF
fscanf(fp, "%d", &G.e);
for (i = 0; i < G.e; i++)
{
fscanf(fp, "%d%d%d", &v1, &v2, &w);
//Insert Edges
G.edges[v1][v2] = w;
G.edges[v2][v1] = w;//若为无向边,则对称位置权值相等
}
/*顶点有数据的话,则读入数据*/
fgetc(fp);//消化输入的换行符
for (i = 0; i < G.n; i++)
{
G.vex[i].num = i;//顶点编号
//getchar();//消化输入的换行符
fscanf(fp, "%c", &G.vex[i].info);//顶点其他信息
}
}
int Prime(MGraph g, int v0)
{
int lowcost[maxSize], vset[maxSize],vpath[maxSize];
int i, j, k, min,sum = 0;
for (i = 0; i < g.n; ++i)
{
lowcost[i] = g.edges[v0][i];
vset[i] = 0;
if (lowcost[i] < INF)
vpath[i] = v0;
else
vpath[i] = -1;
}
vset[v0] = 1;
for (i = 0; i < g.n - 1; ++i)
{
min = INF;
for (j = 0; j < g.n; ++j)
if (vset[j] == 0 && lowcost[j] < min)
{
min = lowcost[j];
k = j;
}
sum += min;
vset[k] = 1;
printf("(%d,%d)", vpath[k], k);
for (j = 0; j < g.n; ++j)
if (vset[j] == 0 && g.edges[k][j] < lowcost[j])
{
lowcost[j] = g.edges[k][j];
vpath[j] = k;
}
}
return sum;
}
int main()
{
int sum;
BuildGraph();
printf("Path:");
sum = Prime(G, 0);
printf("\nSum:%d\n", sum);
system("pause");
}
测试结果(Perfect!):