题目传送门
题目:
n个点,每个点有一个权值 。初始时没有边。
把点 和点 连接起来需要花费 的代价。
有一些额外条件:把点 和点 连接起来需要花费 。
额外条件可以使用,也可以不使用。
想构成一个连通图,求最小代价。
数据范围: , , 。
题解:
把a从小到大排序。
先把m条边都加上,在以1为起点,2~n为终点建立n-1条边。
现在图上有m+n-1条边连接着n个点。
当m>0时,显然边数是多的,可以去掉一些。
m+n-1条边做最小生成树就是答案。
扫描二维码关注公众号,回复:
9153149 查看本文章
感受:
我好弱。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 2e5 + 5 ;
int n , m ;
int pre[maxn] ;
struct node
{
ll x ;
int id ;
bool operator < (const node &s) const
{
return x < s.x ;
}
} a[maxn] ;
struct Edge
{
int u , v ;
ll w ;
bool operator <(const Edge &s) const
{
return w < s.w ;
}
} edge[maxn << 1] ; //����Ҫ��2����Ϊ����Ҫ˫���dfs��
int find(int u)
{
if(pre[u] == u) return u ;
return pre[u] = find(pre[u]) ;
}
void join(int x,int y)
{
int fx = find(x) ;
int fy = find(y) ;
if(fx != fy) pre[fx] = fy ;
}
ll kruskal()
{
ll ans = 0 , cnt = 0 ;
sort(edge + 1 , edge + m + 1) ;
for(int i = 1 ; i <= m ; i ++)
{
if(cnt == n - 1) break ;
int ru = find(edge[i].u) , rv = find(edge[i].v) ;
if(ru == rv) continue ;
ans += edge[i].w , pre[rv] = ru , cnt ++ ;
}
return ans ;
}
int main()
{
scanf("%d%d" , &n , &m) ;
for(int i = 1 ; i <= n ; i ++)
scanf("%lld" , &a[i].x) , a[i].id = i ;
for(int i = 1 ; i <= n ; i ++) pre[i] = i ;
for(int i = 1 ; i <= m ; i ++)
scanf("%d%d%lld" , &edge[i].u , &edge[i].v , &edge[i].w) ;
sort(a + 1 , a + n + 1) ;
for(int i = 1 ; i <= n - 1 ; i ++)
edge[m + i].u = a[1].id , edge[m + i].v = a[i + 1].id ,
edge[m + i].w = a[1].x + a[i + 1].x ;
m += n - 1 ;
ll ans = kruskal() ;
printf("%lld\n" , ans) ;
}