题目
在n个城市之间原本要规划修建许多条下水管道,管理人员发现这些管道会形成一条回 路,而下水道只要将城市联通即可,所以回路会加大施工的成本。所以希望你来帮忙找 出多余的管道来进行优化。当然管道和管道之间是有区别的,比如用s来表示i到j 的管道管理费用,8i越小则表示该管道管理费用越低。能否去除一些管线,使得总管理 成本最低。求出最低的管理成本(不存在自身与自身成为回路的管道)。
格式
输入格式:
第一行有两个数n和k表示城市数量和管道数量;
输出格式:
一个正整数,最低管理成本。 接下来k行,每行都有三个数i,j,c表示城市i和城市j之间的管道成本为c。
样例
输入:
3 3 1 2 3 1 3 5 2 3 8输出:
8
备注
其中1<n,k<100
代码
本题的知识点为并查集+kruskal算法,先将边进行从大到小的排序,然后依次加入到生成树中。加入时要通过并查集判断两个顶点是否位于同一个集合当中,如果是,则会构成回路,不加入;如果不是,则加入,同时更新并查集。
#include <bits/stdc++.h>
using namespace std;
const int N=1e2+7;
struct NODE{
int i,j,c;
bool operator<(const NODE &t) const {return c<t.c;}
}p[N];
//并查集工作
int fa[N],n,k,ans;
void init() //初始时候每一点都是一个集合,这里的fa[i]是表示不同的点处于孤立状态
{
for(int i=1;i<N;i++)
{
fa[i]=i;
}
}
int find(int x) //fa[x]不等于x了,表明x已经不是初始的孤立状态了,已经经过合并进入别的集合了,这时要找出x的集合
{
return x==fa[x]?x:(fa[x]=find(fa[x])); //fa[x]=find(fa[x])很好理解,就是再去找出fa[x]所在的集合
}
void mer(int x,int y) //并查集的合并操作
{
x=find(x),y=find(y);
if(x!=y)
{
fa[x]=y;
}
}
int main()
{
init();
cin>>n>>k; //n为城市数量,k为管道数量
for(int i=0;i<k;i++)
{
cin>>p[i].i>>p[i].j>>p[i].c;
}
sort(p,p+k); //以边权重对管道进行排序
for(int i=0;i<k;i++)
{
if(find(p[i].i)!=find(p[i].j))
{
ans+=p[i].c;
mer(p[i].i,p[i].j);
}
}
cout<<ans;
return 0;
}
ps:本题解题过程中参考了b站up主:轩哥码题,大家详情可看up的视频,附上up讲题视频链接:【码蹄集进阶塔全题解13】数据结构:并查集/线段树/树状数组 MT2137 – MT2143_哔哩哔哩_bilibili