以下是使用C语言编写的代码实现在n个城市之间建设网络,并采用普利姆算法和克鲁斯卡尔算法求解最经济的架设方法。

#include <stdio.h>
#include <stdlib.h>

// 定义最大城市数
#define MAX_CITY 10

// 定义邻接表的结点结构
typedef struct Node {
    int city;  // 城市编号
    int distance;  // 城市之间的距离
    struct Node* next;  // 指向下一个结点的指针
} Node;

// 定义邻接表的头结点结构
typedef struct HeadNode {
    struct Node* first;  // 指向第一个结点的指针
} HeadNode;

// 定义边的结构
typedef struct Edge {
    int city1;  // 城市1
    int city2;  // 城市2
    int distance;  // 城市之间的距离
} Edge;

// 定义并查集的结点结构
typedef struct UnionFindNode {
    int parent;  // 结点的父结点
    int rank;  // 结点的秩
} UnionFindNode;

// 初始化邻接表的头结点数组
void initHeadNodes(HeadNode* headNodes, int n) {
    for (int i = 0; i < n; i++) {
        headNodes[i].first = NULL;
    }
}

// 向邻接表中插入边
void insertEdge(HeadNode* headNodes, int city1, int city2, int distance) {
    // 创建新结点
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->city = city2;
    newNode->distance = distance;
    newNode->next = headNodes[city1].first;
    headNodes[city1].first = newNode;
}

// 打印邻接表
void printAdjacencyList(HeadNode* headNodes, int n) {
    for (int i = 0; i < n; i++) {
        printf("城市%d:", i);
        Node* node = headNodes[i].first;
        while (node != NULL) {
            printf(" 城市%d 距离%d", node->city, node->distance);
            node = node->next;
        }
        printf("\n");
    }
}

// 初始化并查集
void initUnionFind(UnionFindNode* unionFind, int n) {
    for (int i = 0; i < n; i++) {
        unionFind[i].parent = i;
        unionFind[i].rank = 0;
    }
}

// 查找结点的根结点(路径压缩)
int findRoot(UnionFindNode* unionFind, int x) {
    if (unionFind[x].parent != x) {
        unionFind[x].parent = findRoot(unionFind, unionFind[x].parent);
    }
    return unionFind[x].parent;
}

// 合并两个集合(按秩合并)
void unionSets(UnionFindNode* unionFind, int x, int y) {
    int rootX = findRoot(unionFind, x);
    int rootY = findRoot(unionFind, y);
    if (rootX != rootY) {
        if (unionFind[rootX].rank > unionFind[rootY].rank) {
            unionFind[rootY].parent = rootX;
        } else if (unionFind[rootX].rank < unionFind[rootY].rank) {
            unionFind[rootX].parent = rootY;
        } else {
            unionFind[rootY].parent = rootX;
            unionFind[rootX].rank++;
        }
    }
}

// 比较两个边的权重(用于排序)
int compareEdges(const void* a, const void* b) {
    Edge* edgeA = (Edge*)a;
    Edge* edgeB = (Edge*)b;
    return edgeA->distance - edgeB->distance;
}

// 使用普利姆算法构建最小生成树,并返回总权重
int prim(HeadNode* headNodes, int n) {
    int* visited = (int*)calloc(n, sizeof(int));  // 标记结点是否被访问过
    visited[0] = 1;  // 从第一个结点开始
    int totalWeight = 0;  // 总权重
    for (int i = 0; i < n - 1; i++) {
        int minDistance = INT_MAX;  // 最小距离
        int minCity1, minCity2;  // 最小距离对应的城市
        for (int j = 0; j < n; j++) {
            if (visited[j]) {
                Node* node = headNodes[j].first;
                while (node != NULL) {
                    if (!visited[node->city] && node->distance < minDistance) {
                        minDistance = node->distance;
                        minCity1 = j;
                        minCity2 = node->city;
                    }
                    node = node->next;
                }
            }
        }
        visited[minCity2] = 1;
        totalWeight += minDistance;
        printf("最小生成树边: 城市%d - 城市%d 距离%d\n", minCity1, minCity2, minDistance);
    }
    free(visited);
    return totalWeight;
}

// 使用克鲁斯卡尔算法构建最小生成树,并返回总权重
int kruskal(Edge* edges, int n, int m) {
    qsort(edges, m, sizeof(Edge), compareEdges);  // 对边按权重进行排序
    UnionFindNode* unionFind = (UnionFindNode*)malloc(n * sizeof(UnionFindNode));
    initUnionFind(unionFind, n);
    int totalWeight = 0;  // 总权重
    int edgeCount = 0;  // 边的计数器
    for (int i = 0; i < m; i++) {
        if (findRoot(unionFind, edges[i].city1) != findRoot(unionFind, edges[i].city2)) {
            unionSets(unionFind, edges[i].city1, edges[i].city2);
            totalWeight += edges[i].distance;
            edgeCount++;
            printf("最小生成树边: 城市%d - 城市%d 距离%d\n", edges[i].city1, edges[i].city2, edges[i].distance);
            if (edgeCount == n - 1) {
                break;
            }
        }
    }
    free(unionFind);
    return totalWeight;
}

int main() {
    int n;  // 城市数
    int m = 0;  // 边数
    printf("输入城市数(至少5个):");
    scanf("%d", &n);
    if (n < 5) {
        printf("错误:城市数不能少于5个。\n");
        return 0;
    }
    Edge* edges = (Edge*)malloc((n * (n - 1) / 2) * sizeof(Edge));  // 最多有n*(n-1)/2条边
    HeadNode* headNodes = (HeadNode*)malloc(n * sizeof(HeadNode));  // 邻接表的头结点数组
    initHeadNodes(headNodes, n);
    printf("输入城市之间的距离:\n");
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            printf("城市%d - 城市%d:", i, j);
            int distance;
            scanf("%d", &distance);
            insertEdge(headNodes, i, j, distance);
            insertEdge(headNodes, j, i, distance);
            edges[m].city1 = i;
            edges[m].city2 = j;
            edges[m].distance = distance;
            m++;
        }
    }
    printf("邻接表:\n");
    printAdjacencyList(headNodes, n);
    printf("普利姆算法最小生成树:\n");
    int primWeight = prim(headNodes, n);
    printf("总权重:%d\n", primWeight);
    printf("克鲁斯卡尔算法最小生成树:\n");
    int kruskalWeight = kruskal(edges, n, m);
    printf("总权重:%d\n", kruskalWeight);
    free(edges);
    free(headNodes);
    return 0;
}

解释:

  1. 定义了邻接表的结点结构Node和邻接表的头结点结构HeadNode,以及边的结构Edge和并查集的结点结构UnionFindNode。

  2. 初始化邻接表的头结点数组initHeadNodes函数,将所有头结点的first指针初始化为NULL。

  3. 向邻接表中插入边insertEdge函数,将边插入到对应的头结点链表中。

  4. 打印邻接表printAdjacencyList函数,按照邻接表的结构打印出城市之间的距离。

  5. 初始化并查集initUnionFind函数,将每个结点的parent初始化为自身,rank初始化为0。

  6. 查找结点的根结点findRoot函数,采用路径压缩的方式查找根结点,同时更新结点的parent指向根结点。

  7. 合并两个集合unionSets函数,按照秩的大小合并两个结点所属的集合,并更新根结点的parent和rank。

  8. 比较两个边的权重compareEdges函数,用于对边进行排序。

  9. 使用普利姆算法prim函数,通过循环选择最小距离的边,并将其加入最小生成树中,直到生成树包含n-1条边。

  10. 使用克鲁斯卡尔算法kruskal函数,先将所有边按权重进行排序,然后遍历每条边,如果两个顶点不在同一个集合中,则将边加入最小生成树中。

  11. 主函数main,首先输入城市数n,并根据城市数动态分配边的数组和邻接表的头结点数组的内存。

  12. 输入城市之间的距离,并通过insertEdge函数将边插入邻接表中,并将边加入边的数组中。

  13. 打印邻接表。

  14. 使用普利姆算法求解最小生成树的总权重。

  15. 使用克鲁斯卡尔算法求解最小生成树的总权重。

  16. 释放动态分配的内存。

注意:此代码假设输入的城市之间的距离都是非负整数

请使用c语言编写一个代码以实现在n个城市n=5之间建设网络只需保证连通即可要求最经济的架设方法。并对每行代码做出解释1手动录入城市数nn=5及各城市之间的距离并将其储存起来。2存储结构需采用邻接表和邻接矩阵两种。3在代码编写时需要采用普利姆算法和克鲁斯卡尔算法两种。4输出所得的邻接表或邻接矩阵。5输出所得的最小生成树。

原文地址: https://www.cveoy.top/t/topic/hGfB 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录