題解 CF1095F 【Make It Connected】
阿新 • • 發佈:2020-12-10
Solution CF1095F Make It Connected
題目大意:給定 \(n\) 個點,每個點有一個點權 \(a_i\),在 \(i,j\) 之間連邊的代價為 \(a_i + a_j\)。除此之外,還給定了額外 \(m\) 條邊。求最小代價使得原圖聯通。
貪心,最小生成樹
分析:首先考慮 \(m=0\) 的做法
我們直接貪心,選取 \(a\) 最小的點作為中心,建出一個菊花圖,這樣一定是最優的。
證明考慮歸納法,類似於 Prim 演算法的思想
對於 \(n = 2\) 的情況顯然
對於 \(n > 2\),前 \(n - 1\) 個點已經形成了一棵生成樹,我們就要把當前點接到樹上。當前點的點權是不變的,我們肯定貪心去選樹上點權最小的點。
這樣找出一棵生成樹之後,我們再把 \(m\) 條邊加入,一起跑最小生成樹就可以了
#include <cstdio> #include <cctype> #include <vector> #include <algorithm> using namespace std; typedef long long ll; constexpr int maxn = 2e5 + 100; typedef long long ll; struct IO{//-std=c++11,with cstdio and cctype private: static constexpr int ibufsiz = 1 << 20; char ibuf[ibufsiz + 1],*inow = ibuf,*ied = ibuf; static constexpr int obufsiz = 1 << 20; char obuf[obufsiz + 1],*onow = obuf; const char *oed = obuf + obufsiz; public: inline char getchar(){ #ifndef ONLINE_JUDGE return ::getchar(); #else if(inow == ied){ ied = ibuf + sizeof(char) * fread(ibuf,sizeof(char),ibufsiz,stdin); *ied = '\0'; inow = ibuf; } return *inow++; #endif } template<typename T> inline void read(T &x){ static bool flg;flg = 0; x = 0;char c = getchar(); while(!isdigit(c))flg = c == '-' ? 1 : flg,c = getchar(); while(isdigit(c))x = x * 10 + c - '0',c = getchar(); if(flg)x = -x; } template <typename T,typename ...Y> inline void read(T &x,Y&... X){read(x);read(X...);} inline int readi(){static int res;read(res);return res;} inline long long readll(){static long long res;read(res);return res;} inline void flush(){ fwrite(obuf,sizeof(char),onow - obuf,stdout); fflush(stdout); onow = obuf; } inline void putchar(char c){ #ifndef ONLINE_JUDGE ::putchar(c); #else *onow++ = c; if(onow == oed){ fwrite(obuf,sizeof(char),obufsiz,stdout); onow = obuf; } #endif } template <typename T> inline void write(T x,char split = '\0'){ static unsigned char buf[64]; if(x < 0)putchar('-'),x = -x; int p = 0; do{ buf[++p] = x % 10; x /= 10; }while(x); for(int i = p;i >= 1;i--)putchar(buf[i] + '0'); if(split != '\0')putchar(split); } inline void lf(){putchar('\n');} ~IO(){ fwrite(obuf,sizeof(char),onow - obuf,stdout); } }io; struct edge{int u,v;ll d;}; vector<edge> edges; int n,m; ll v[maxn]; namespace mset{ int f[maxn]; inline void init(){for(int i = 1;i <= n;i++)f[i] = i;} inline int find(const int x){return x == f[x] ? x : f[x] = find(f[x]);} inline void merge(const int a,const int b){ const int x = find(a),y = find(b); f[x] = y; } } ll ans; inline void kruskal(){ mset::init(); sort(edges.begin(),edges.end(),[](const edge &a,const edge &b){ return a.d < b.d; }); for(auto e : edges){ if(mset::find(e.u) == mset::find(e.v))continue; ans += e.d; mset::merge(e.u,e.v); } } int p = 1; int main(){ io.read(n,m); for(int i = 1;i <= n;i++)io.read(v[i]); for(int i = 1;i <= n;i++) if(v[i] < v[p])p = i; for(int i = 1;i <= n;i++) if(i != p)edges.push_back(edge{i,p,v[i] + v[p]}); for(int u,v,i = 1;i <= m;i++){ io.read(u,v);const ll d = io.readll(); edges.push_back(edge{u,v,d}); } kruskal(); io.write(ans,'\n'); return 0; }