问题
在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得的 w(T) 最小,则此 T 为 G 的最小生成树。
请实现最小生成树算法。
解析
Prim算法:
Prim算法又称“加点法”,用于边数较多的带权无向连通图
方法:每次找与之连线权值最小的顶点,将该点加入最小生成树集合中
注意:相同权值任选其中一个即可,但是不允许出现闭合回路的情况。
kruskal(克鲁斯卡尔)算法:
kruskal算法又称“加边法”,用于边数较少的稀疏图
方法:每次找图中权值最小的边,将边连接的两个顶点加入最小生成树集合中
注意:相同权值任选其中一个即可,但是不允许出现闭合回路的情况。
实现
//定义
#define MAX_SIZE 10
typedef struct node * graphPointer;
typedef struct node {
int weight;
int id;
graphPointer link;
};
//最小生成树——Prim算法
void prim(graphPointer* graph, int vn) {
int pointSet[MAX_SIZE+1] = {0};//现有点集
int i, j;
int w;//代价
int targetV;//目标点
int startV; //起始点
graphPointer temp;
printf("Prim:\n");
//从1号点开始
pointSet[1] = 1;
for (i = 1; i < vn; i++) {
w = 10000;//假设每条边的权重均小于10000;
//找到从现有点集出发的能够以最小代价达到的点
for (j = 1; j < vn + 1; j++) {
if (pointSet[j] == 1) {
temp = graph[j];
//找到从j出发的能够以最小代价达到的点
while (temp != NULL) {
if (temp->weight < w && pointSet[temp->id]!=1) {
w = temp->weight;
targetV = temp->id;
startV = j;
}
temp = temp->link;
}
}
}
pointSet[targetV] = 1;
printf("%d --- %d\n",startV,targetV);
}
}
//最小生成树——Kruskal算法
void kruskal(graphPointer* graph, int vn) {
int i, j, k;
int w;//代价
int targetV;//目标点
int startV; //起始点
graphPointer temp,ptr1,ptr2,ptr;
int flag1, flag2;
//初始化树群
graphPointer* tree = (graphPointer*)malloc(sizeof(graphPointer*)*(vn + 1));
//因为0号不用,所以多申请一个
for (i = 1; i < vn + 1; i++) {
ptr = (graphPointer)malloc(sizeof(node));
ptr->id = i;
ptr->link = NULL;
tree[i] = ptr;
}
int trees[MAX_SIZE][MAX_SIZE] = {0};
for (i = 1; i < vn + 1; i++) {
trees[i][i] = 1;//自身可达
}
printf("Kruskal:\n");
for (i = 1; i < vn; i++) {
w = 10000;//假设每条边的权重均小于10000;
//找到一条不在现有集合中的最小边
for (j = 1; j < vn + 1; j++) {
temp = graph[j];
while (temp != NULL) {
if (temp->weight <= w) {
//树群校验
if (trees[j][temp->id] == 1) {
//存在回路
}
else {
w = temp->weight;
targetV = temp->id;
startV = j;
}
}
temp = temp->link;
}
}
//更新树群,先更新代表,再更新可达节点
for (k = 1; k < MAX_SIZE; k++) {
if (trees[startV][k]) {
trees[targetV][k] = 1;
}
else if (trees[targetV][k]) {
trees[startV][k] = 1;
}
}
for (j = 1; j < MAX_SIZE; j++) {
if (trees[startV][j]) {
for (k = 1; k < MAX_SIZE; k++) {
if (trees[targetV][k]) {
trees[j][k] = 1;
}
}
}
}
for (j = 1; j < MAX_SIZE; j++) {
if (trees[targetV][j]) {
for (k = 1; k < MAX_SIZE; k++) {
if (trees[startV][k]) {
trees[j][k] = 1;
}
}
}
}
printf("%d --- %d %d\n", startV, targetV,w);
}
}