Codeforces 1095F Make It Connected 【MST】

<题目链接>

题目大意:

给定一张$n$个顶点(每个顶点有点权)的无向图,并且给出边权为$w_i$的m条边,顶点$u$和顶点$v$直接如果建边,边权为$a_u + a_v$,求图连通的最小边权和。

解题分析:

可以发现,如果仅仅只是考虑根据点权连边的话,那么最优的情况就是所有点(除点权最小的点)与点权最小的点相连。如果加上题目给出的边权综合考虑,我们就是将这m+n-1条边加入考虑的范围内,然后根据这些边建一颗最小生成树。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3  
 4 typedef long long ll;
 5 #define N int(2e5+7)
 6 #define rep(i,s,t) for(int i=s;i<=t;i++)
 7 int n,m,pre[N];
 8 ll val[N];
 9  
10 struct Edge{
11     int fi,se;
12     ll cost;
13     Edge(int _fi=0,int _se=0,ll _cost=0):fi(_fi),se(_se),cost(_cost){}
14     bool operator<(const Edge & tmp)const {
15         return cost<tmp.cost;
16     }
17 }edge[N<<1];     //最多只用考虑m+n-1条边
18  
19 vector<Edge>vec;
20  
21 int find(int x){ return pre[x]==x?x:pre[x]=find(pre[x]); }
22  
23 void Kruskal(){
24     ll sum=0,cnt=0;
25     sort(vec.begin(),vec.end());
26     for(int i=0;i<vec.size();i++){
27         Edge now=vec[i];
28         int f1=find(now.fi),f2=find(now.se);
29         if(f1!=f2){
30             pre[f1]=f2;
31             sum+=now.cost;
32             cnt++;
33         }
34         if(cnt>=n-1)break;
35     }
36     printf("%lld
",sum);
37 }
38  
39 int main(){
40     scanf("%d%d",&n,&m);
41     ll mn=1e18;int mnloc=-1;
42     rep(i,1,n){
43         scanf("%lld",&val[i]);
44         pre[i]=i;
45         if(val[i]<mn)mn=val[i],mnloc=i;     //记录最小的节点序号和权值
46     }
47     rep(i,1,m){
48         int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);
49         vec.push_back(Edge(u,v,w));       //真实的边权
50     }  
51     rep(i,1,n){
52         if(i==mnloc)continue;
53         vec.push_back(Edge(i,mnloc,val[i]+mn));     //点间连边的点权之和
54     }
55     Kruskal();
56 }

  

2019-02-21

原文地址:https://www.cnblogs.com/00isok/p/10410486.html