2.现在某电信公司要对如下图的几个城市之间进行光纤连接布线,请用合适的存储结构将下图存储到计算机中方便进行处理。 1541039920970057833.png 3.现在公司想以最小的代价将所有城市连通,方便所有城市间通信,请用普里姆算法和克鲁斯卡尔算法实现本图的最小生成树(此类算法为贪心算法)。 4、同时所有同学需要掌握无负边无自环的图的并查集的应用。
时间: 2024-02-06 22:12:07 浏览: 209
图的最小生成树 普里姆算法+克鲁斯卡尔算法
3星 · 编辑精心推荐
2. 该图可以使用邻接矩阵或邻接表来存储。下面是邻接矩阵的示例代码:
```
int graph[6][6] = {
{0, 6, 1, 5, INF, INF},
{6, 0, 5, INF, 3, INF},
{1, 5, 0, 5, 6, 4},
{5, INF, 5, 0, INF, 2},
{INF, 3, 6, INF, 0, 6},
{INF, INF, 4, 2, 6, 0}
};
```
其中,INF表示两个节点之间不存在边。
3. 普里姆算法和克鲁斯卡尔算法的实现代码如下:
```c++
// Prim算法求解最小生成树
void prim(int graph[][6], int n) {
int parent[n]; // 记录每个节点的父节点
int key[n]; // 记录每个节点到生成树的最小距离
bool visited[n]; // 记录每个节点是否已经加入生成树
// 初始化
for (int i = 0; i < n; i++) {
key[i] = INF;
visited[i] = false;
}
key[0] = 0; // 选定0号节点作为起点
parent[0] = -1; // 根节点没有父节点
for (int i = 0; i < n - 1; i++) {
// 选取key值最小的节点
int min_key = INF;
int u;
for (int j = 0; j < n; j++) {
if (!visited[j] && key[j] < min_key) {
min_key = key[j];
u = j;
}
}
visited[u] = true;
// 更新与u相邻的节点的key值和parent
for (int v = 0; v < n; v++) {
if (graph[u][v] != INF && !visited[v] && graph[u][v] < key[v]) {
parent[v] = u;
key[v] = graph[u][v];
}
}
}
// 输出最小生成树的边
for (int i = 1; i < n; i++) {
cout << parent[i] << " - " << i << " : " << graph[i][parent[i]] << endl;
}
}
// Kruskal算法求解最小生成树
void kruskal(int graph[][6], int n) {
int parent[n]; // 记录每个节点的父节点
int rank[n]; // 记录每个节点所在集合的秩
// 初始化
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 0;
}
// 将边按权值从小到大排序
vector<pair<int, pair<int, int>>> edges;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (graph[i][j] != INF) {
edges.push_back(make_pair(graph[i][j], make_pair(i, j)));
}
}
}
sort(edges.begin(), edges.end());
// 依次加入边,保证生成树不出现环
for (int i = 0; i < edges.size(); i++) {
int u = edges[i].second.first;
int v = edges[i].second.second;
int w = edges[i].first;
int parent_u = find(parent, u);
int parent_v = find(parent, v);
if (parent_u != parent_v) {
cout << u << " - " << v << " : " << w << endl;
union_set(parent, rank, parent_u, parent_v);
}
}
}
// 查找节点所在集合的根节点
int find(int parent[], int i) {
if (parent[i] != i) {
parent[i] = find(parent, parent[i]);
}
return parent[i];
}
// 合并两个集合
void union_set(int parent[], int rank[], int x, int y) {
int root_x = find(parent, x);
int root_y = find(parent, y);
if (root_x == root_y) {
return;
}
if (rank[root_x] < rank[root_y]) {
parent[root_x] = root_y;
} else if (rank[root_x] > rank[root_y]) {
parent[root_y] = root_x;
} else {
parent[root_y] = root_x;
rank[root_x]++;
}
}
```
4. 并查集可以用于判断两个节点是否连通,具体实现代码如下:
```c++
// 判断两个节点是否连通
bool is_connected(int parent[], int x, int y) {
return find(parent, x) == find(parent, y);
}
// 查找节点所在集合的根节点
int find(int parent[], int i) {
if (parent[i] != i) {
parent[i] = find(parent, parent[i]);
}
return parent[i];
}
// 合并两个集合
void union_set(int parent[], int rank[], int x, int y) {
int root_x = find(parent, x);
int root_y = find(parent, y);
if (root_x == root_y) {
return;
}
if (rank[root_x] < rank[root_y]) {
parent[root_x] = root_y;
} else if (rank[root_x] > rank[root_y]) {
parent[root_y] = root_x;
} else {
parent[root_y] = root_x;
rank[root_x]++;
}
}
```
阅读全文