codeforces1095F 2000分图论

题目传送门

题目:

n个点,每个点有一个权值 \dpi{150}a_i 。初始时没有边。

把点 i 和点 j 连接起来需要花费 a_i + a_j 的代价。

有一些额外条件:把点 i 和点 j 连接起来需要花费 w 。

额外条件可以使用,也可以不使用。

想构成一个连通图,求最小代价。

数据范围:1\leqslant n\leqslant 2\cdot 10^5  , 0\leqslant m\leqslant 2\cdot 10^5 , 1\leqslant a_i \;,\; w\leqslant 10^{12} 。

题解:

把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) ;
}
发布了215 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/104200428
今日推荐