1348:【例4-9】城市公交网建设问题

【解题思路】

该题难点是要保存最小生成树的所有边,对于不同的求最小生成树的算法,有不同的方法来完成。

【参考代码】

prim算法

#include<bits/stdc++.h>
using namespace std;
const int N = 105; // 定义常量 N,表示数组大小
int n, e, x, y, w;
int g[N][N]; // 保存图的邻接矩阵
int ans[N]; // 记录当前最小生成树中每个点的父亲节点编号
bool v[N];   // 标记哪些点已经在MST中
struct nod {
    int to, w;
    bool operator < (const nod &b) const { // 重载小于号运算符,使得该结构体对象可被优先队列使用(小根堆)
        return w > b.w;  // 按权值从小到大排序
    }
}; 
void prim() {
    priority_queue<nod> pq;
    pq.push({1, 0}); // 将结点 1 加入最小生成树中,其父亲节点为 0
 
    while (!pq.empty()) {
        nod t = pq.top();
        pq.pop();
        if (v[t.to]) continue; // 如果已经在最小生成树中,则忽略
        v[t.to] = true; // 标记该结点已加入MST
        if (t.w != 0) { // 输出点与其父亲节点之间的边
            cout << ans[t.to] << " " << t.to << endl;
        }
 
        for (int i = 1; i <= n; i++) { // 枚举所有未访问过的结点
            if (!v[i] && g[t.to][i] < 0x3f3f3f3f) { // 如果可从 t.to 到达i,并且 i 未被访问过
                pq.push({i, g[t.to][i]}); // 将 i 加入优先队列
                if (g[t.to][i] < g[ans[i]][i]) ans[i] = t.to; // 更新当前最短距离
            }
        }
    }
}
 
int main() {
    cin >> n >> e;
    memset(g, 0x3f, sizeof g); // 初始化邻接矩阵为正无穷
    for (int i = 1; i <= e; i++) {
        cin >> x >> y >> w;
        g[x][y] = g[y][x] = w; // 读入边信息,建立双向边
    }
    for (int i = 1; i <= n; i++) ans[i] = i; // 最开始每个点的父亲节点都是自己
    prim(); // 运行 Prim 算法求解最小生成树
    return 0;
}
Kruskal算法
#include <iostream>  
#include <algorithm>  
#include <vector>  
using namespace std;  
const int MAX_N = 100;  
const int MAX_M = 10000;    
int n, m;
  
 
struct Edge {  
    int u, v;  
    int len;  
};  

vector<Edge> MST; // 用于存储最小生成树的边  
Edge E[MAX_M]; // 存储所有边的数组  
int fa[MAX_N]; // 并查集的父节点数组 
     
bool cmp(Edge a, Edge b) {  // 按边长从小到大排序 
    return a.len < b.len;  
}  

void init() {  
    for (int i = 1; i <= n; i++) {  
        fa[i] = i;  
    }  
} 
   
int find(int x) { // 路径压缩 
	while (fa[x] != x) x = fa[x];
	return x;
} 

void unionn(int x, int y) {  // 合并集合 
    fa[y] = x;      
} 

int kruskal() {  
    int sum = 0; // 最小生成树的权值和  
    init(); // 初始化并查集  
    sort(E, E + m, cmp); // 对边进行排序  
    for (int i = 0; i < m; i++) {  
        int u = find(E[i].u);  
        int v = find(E[i].v);   
        if (u != v) { // 如果u和v不在同一个集合中  
            unionn(u,v); // 合并集合  
            MST.push_back({E[i].u, E[i].v, E[i].len}); // 将边加入到最小生成树中  
            sum += E[i].len; // 更新权值和  
        }  
    }  
    return sum; // 返回最小生成树的权值和  
}  
  
int main() {  
    cin >> n >> m; // 输入顶点数和边数  
    for (int i = 0; i < m; i++) { // 输入每条边的信息  
        cin >> E[i].u >> E[i].v >> E[i].len; // 输入起点、终点和长度,并存储到边数组中  
    }  
    int totalCost = kruskal(); // 调用Kruskal算法计算最小生成树的权值和    
    for (int i=0;i<n-1;i++) { // 遍历最小生成树中的边  
        cout << MST[i].u << " " << MST[i].v << endl; // 输出边的信息  
    }  
    return 0; // 程序结束返回0  
}

c++城市公交查询系统 1.设有一文件对象in_file,若在while循环中用in_file>> 每次从文件中得到一个字符串直到文件结束, 如果用in_file直接来判断文件是否结束, 则文件末的那个字符串会得到两次。 而用文件in_file.eof()来判断则会得到正确的结果。 2.用delete []释放字符串空间时,老是有问题, 其中的原因之一是你原来申请的空间不够大, 后来往这个空间中放了过多的内容以至越界, 这时候会发生运行时的错误。 3.把一个对象作为参数传给另一个对象的成员函数时, 程序不能正常结束,即系统删除对象时有问题; 而使用指针或者引用传递参数时不仅不会出现问题, 而且可以人为的删除对象。 我个人认为这很有可能是值传递的原因, 当把一个对象作为实参传给一个函数时,函数形参拷贝了实参的值, 这时,如果对象有指针成员,那么形参的指针成员的值和 实参的指针成员的值将完全一样, 即它们指向的是同一块内存,所以当函数调用结束的时候, 函数的形参将会被系统撤消, 这时,形参调用析构函数,释放用new动态申请的内存。在函数的外面, 作为实参的对象的指针成员其实已经被撤消了,所以当程序结束, 系统撤消这个对象时,这个对象又要调用析构函数来释放指针成员, 但这时指针其实已经指向了非法的空间,导致出错。 bus 文件夹的内容记录的是每条线路的信息,对应于bus 类。 每个文件以线路名称(即车名,忽略前面的k)命名。 每个文件的内容组织如下:(共分为6行,以回车键作为行结束标志) 第一行为“线路名称:#### ”,其中####用具体的线路名称代替; 第二行为“上行站点:####”。 第三行为“下行站点:####”。 第四行为“首班车时间:####”。 第五行为“末班车时间:####”。 第六行为“票价:####”。 注:若不分“上行站点”和“下行站点”, 则第二行为“站点名称:####”, 第三行为空行;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值