https://codeforces.com/problemset/problem/1095/F
题意
给你n个互不相通的点,每个点有权值ai,题目要求将n个点连接生成最小生成树,连接两点的代价是这两个点的权值之和,但是,题目又给你m个特惠,每一个特惠都指定两个点一个特价:x,y,w,他们相连接不一定要以权值为代价,可以使用特价w代替,求代价最小值。
思路
- 使用kul建立最小生成树
- 选出权值最小的点,e[++t]记录它与其他所有点,以及这两点连接的代价
- e[++t]记录特惠。
- 针对数组e的w进行从小到大的快排
- fa[i] = i ( i 从1到n)
- for(i , 1 , t) (遍历e数组)
- 并查集的内容,记录连接次数
- 连接次数到n-1就退出
- 输出答案
- 用prim的话,你得做加边操作(可能用到前向星(数组模拟邻接表)),然后循环n-1次,每次去遍历当前节点的连接边,太过麻烦,而且这题是稀疏图,适合使用kul算法。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;
struct node{
int u,v,w;
bool operator < (const node& A) const{
return w < A.w;
}
}e[N];
int fa[N],a[N],MinIndex,Min = inf,t,times,ans;
int find(int x){
if (fa[x] != x) return fa[x] = find(fa[x]);
return x;
}
signed main()
{
ios::sync_with_stdio(false);
int n,m;
cin >> n >> m;
for (int i = 1; i <= n ;i++){
cin >> a[i];
if (Min > a[i])
Min = a[i],
MinIndex = i;
}
for (int i = 1; i <= n; i++){
if (i != MinIndex)
e[++t].u = MinIndex,
e[t].v = i,
e[t].w = Min + a[i];
}
for (int i = 1; i <= m; i++){
t++;
cin >> e[t].u >> e[t].v >> e[t].w;
}
sort(e+1,e+1+t);
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= t; i++){
int u = e[i].u, v = e[i].v;
if (find(u) != find(v)){
fa[find(u)] = find(v);
ans += e[i].w;
times++;
if (times == n-1) break;
}
}
cout << ans << "\n";
return 0;
}