昨晚被最小生成树的题卡了一晚上,好不容易才搞明白
就以这道题为例吧
线路规划
题目我放到最后
最小生成树有两种算法Kruskal和Prim
两种算法其实都是贪心
还是蒟蒻的我现在还只会Kruskal算法
就只写这一种算法了
最小生成树有两个性质
- 最小生成树不能形成回路
- 最小生成树的边数等于点数减一
Kruskal算法:
1. 快排边长,用贪心的思想每次都优先选取权值较小的边
2. 建立并查集,判断是否连成环。如果两个点已经在一个并查集里面,若连接,就会形成一个环
3. 当边的数量为点的数量减一时,最小生成树已经建成了,退出循环
蒟蒻好不容易通过的代码
int f[101011];//并查集
int n,m,cnt;
ll ans;
struct node
{
int x;
int y;
int val;
}a[101011];
int find(int root)//找根节点
{
while(root != f[root])
{
root = f[root] = f[f[root]];
}
return root;
}
bool cmp(node t1,node t2)
{
return t1.val < t2.val;
//按边的权值升序排列
}
void kruskal()
{
ans=0;
cnt=0;
for(int i=0;i<m;i++)
{
int root1,root2;
root1 = find(a[i].x);
root2 = find(a[i].y);
if(root1 == root2)
{
continue;
//这两个点已经连通,存在于一个并查集中
}
ans += a[i].val;
f[root1] = root2;//合并为一个并查集
if(++cnt == n-1) break;
//循环结束条件:边的数量为点的数量减一
}
}
int main()
{
cin >> n >> m;
for(int i=0;i<n;i++)
{
f[i]=i;
//并查集初始化,每个人是自己的根节点
}
for(int i=0;i<m;i++)
{
cin >> a[i].x >> a[i].y >> a[i].val;
}
sort(a,a+m,cmp);
kruskal();
cout << ans << endl;
return 0;
}
问题 A: 线路规划
时间限制: 1 Sec 内存限制: 128 MB
题目描述
有n 个村庄之间需要架设通信线路,使得任意两个村庄之间均可通信。两个村庄a, b 间可通信,当且仅当它们之间存在一条通信线路或者存在村庄c 使得a,c 和b,c 间均可通信。给出村庄之间架设通信线路的代价,求出最小的总代价。
输入
第一行包含两个整数n,m,分别表示村庄数量和可以架设通信线路的村庄对数。以下m 行,每行三个整数a,b,c,表示村庄a,b之间架设线路的代价为c(村庄从0 开始编号)。
输出
一个整数,最小总代价。
样例输入 Copy
3 3
0 1 1
1 2 1
2 0 3
样例输出 Copy
2
提示
对于50% 的数据,n<=100,m <=n^2
对于全部数据,1<=n<=10^5; n-1<=m<=10^5,所有代价均在[0, 10^6] 范围内,保证问题有解。