1. 程式人生 > >Codeforces Round #529 (Div. 3) F.Make It Connected

Codeforces Round #529 (Div. 3) F.Make It Connected

傳送門

 

題意:

  有 n 個頂點,每個頂點有個花費 a[ i ],連線頂點 u,v 需要花費 a[v]+a[u]的代價。

  有 m 個特殊邊,每條邊有三個引數 u,v,w 代表的意思是連線 u,v 的花費可以不是 a[v]+a[u] 而是 w(當然選擇小的那個啦)。

  求聯通所有的頂點需要的最少花費?

題解:

  首先,需要建圖,改如何建呢?

  考慮到貪心的思路,首先不考慮 m 個特殊邊,如何用最少的花費聯通所有頂點呢?

  答案是找到 a[ i ] 最少的頂點 i,其他 n-1 個頂點全部連向 i 。

  將這 n-1 條邊記錄下來,在加上 m 條特殊邊,然後,就是求最小生成樹的模板題了,emmmmmm

AC程式碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 using namespace std;
 6 #define ll __int64
 7 #define pb(x) push_back(x)
 8 const int maxn=2e5+10;
 9 
10 int n,m;
11 ll a[maxn];
12 struct Node
13 {
14     int u,v;
15     ll w;
16 Node(int a,int b,ll c):u(a),v(b),w(c){} 17 }; 18 vector<Node >G; 19 void addEdge(int u,int v,ll w) 20 { 21 G.pb(Node(u,v,w)); 22 } 23 24 int fa[2*maxn]; 25 int Find(int x) 26 { 27 int r=x; 28 while(r != fa[r]) 29 r=fa[r]; 30 while(fa[x] != r) 31 { 32 int
temp=fa[x]; 33 fa[x]=r; 34 x=temp; 35 } 36 return r; 37 } 38 bool Union(int x,int y) 39 { 40 x=Find(x),y=Find(y); 41 if(x != y) 42 { 43 fa[x]=y; 44 return true; 45 } 46 return false; 47 } 48 bool cmp(Node _a,Node _b) 49 { 50 return _a.w < _b.w; 51 } 52 ll Solve() 53 { 54 sort(G.begin(),G.end(),cmp); 55 ll res=0; 56 for(int i=0;i < G.size();++i) 57 { 58 Node e=G[i]; 59 if(Union(e.u,e.v)) 60 res += e.w; 61 } 62 return res; 63 } 64 int main() 65 { 66 scanf("%d%d",&n,&m); 67 int minP=0; 68 for(int i=1;i <= n;++i) 69 { 70 fa[i]=i; 71 scanf("%I64d",a+i); 72 minP=(minP == 0 || a[minP] > a[i] ? i:minP); 73 } 74 for(int i=1;i <= n;++i) 75 addEdge(i,minP,a[i]+a[minP]); 76 for(int i=1;i <= m;++i) 77 { 78 int u,v; 79 ll w; 80 scanf("%d%d%I64d",&u,&v,&w); 81 addEdge(u,v,w); 82 } 83 printf("%I64d",Solve()); 84 return 0; 85 }
Kruskal