6.5--PTA【 公路村村通 】连通分支合并法解决最小生成树问题(克鲁斯卡尔算法)

#include<iostream>
#include<queue>
#include<algorithm>
#include<math.h>
using namespace std;
#define OK 1
#define ERROR 0
#define Status int
#define inf 0x3f3f3f3f
typedef struct arc
{
    int v0;
    int v1;
    int cost;
}arc;
vector<arc> g;
vector<int> branch;
int sum_cost=0;//最小权值
bool cmp(arc a, arc b)
{
    return a.cost > b.cost;//排序,最小权值的边在末尾
}
void cout_branch_state()
{
    cout << "当前branch数组状态为:";
    for (int i = 1; i < branch.size(); i++) 
    {
        cout << branch[i]<<" ";
    }
    cout << endl;
}
int main()
{
    int n, e;
    cin >> n >> e;//顶点数和边数 顶点从1--n编号
    branch.resize(n + 1);
    g.resize(e);
    for (int i = 1; i <= n; i++)
    {
        branch[i] = i;
    }
    for (int i = 0; i < e; i++)
    {
        cin >> g[i].v0 >> g[i].v1 >> g[i].cost;
    }
    sort(g.begin(), g.end(), cmp);
    
    for (int i = 1; i <= n-1; i++)//找到n-1条边和n个顶点构成最小生成树
    {
        while (g.size())//找到一条符合条件的可插入的边
        {
            arc temp;
            temp = g.back();
            if (branch[temp.v0] == branch[temp.v1])//属于同一连通分支,加入该边会形成圈,应舍弃
            {
                g.pop_back();
            }
            else
            {    
                g.pop_back();
                //将所有和v1处于相同连通分支的节点的连通分支序号变成和v0的连通分支序号相同
                cout_branch_state();
                int want_change = branch[temp.v1];//记录要改变的连通分支序号
                for (int k = 1; k <= n; k++)
                {
                    if (branch[k] == want_change) 
                        branch[k] = branch[temp.v0];
                }
                cout <<" 加入的边为: "<< temp.v0 << " " << temp.v1 << " " << temp.cost << endl;
                cout_branch_state();
                sum_cost += temp.cost;
                break;
            }
        }
    }
    int last_branch_id=branch[1];
    for (int i = 2; i <= n; i++)
    {
        if (branch[i] != last_branch_id)//若所给图不连通,最终结果存在不同连通分支,则输出-1
        {
            cout << -1;
            return 0;
         }
    }
    cout << sum_cost;
    return 0;
}

同样,此方法还可以用于判断无向图的两个顶点之间是否存在路径,如题

#include<iostream>
#include<queue>
#include<algorithm>
#include<math.h>
using namespace std;
#define OK 1
#define ERROR 0
#define Status int
#define inf 0x3f3f3f3f

int main()
{
    int n, e,start,end;
    cin >> n >> e;
    vector<int> graph;
    graph.resize(n);
    int index = 1;
    for (auto& d : graph)
    {
        d = index++;
    }
    for (int i = 1; i <= e; i++)
    {
        int x, y;
        cin >> x >> y;
        if (graph[x] != graph[y])
        {
            int temp = graph[y];
            for (auto& d : graph)
            {
                if (d == temp) d = graph[x];
            }
        }
    }
    cin >> start >> end;
    if(graph[start]==graph[end])
    cout << "There is a path between " << start << " and " << end << ".";
    else 
    cout<< "There is no path between " << start << " and " << end << ".";
    return 0;
}

即:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值