本題看似很難,實際上思路很是簡單——若是你想通了。c++
首先有一個問題:圖中有幾個點?大部分的人會回答\(n\)個點。錯了,有\(n+1\)個。spa
多出來的那個點在哪?關鍵在於你要理解每個決策的意義。實際上,多出來的那個點是地下的自然礦泉水。當咱們打井時,咱們其實是在往地下連邊。理解了這一點,代碼就沒有任何難度了。code
構圖時,咱們只需多加一個點,對於每一個點\(i\),咱們連邊\(i→n+1\),邊權爲\(w_i\)。而後直接跑最小生成樹就沒了。就沒了。(轉載from here)blog
#include<bits/stdc++.h> using namespace std; const int MAXN=300+10; const int MAXM=1e5; int n,m; int fa[MAXN]; struct Node { int u,v,w; bool operator < (const Node &x) const { return x.w>w; } }edge[MAXM]; inline int read() { int tot=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') { tot=tot*10+c-'0'; c=getchar(); } return tot; } inline int find(int k) { if(fa[k]==k)return k; else return fa[k]=find(fa[k]); } inline int kruskal() { int tot=0,cnt=0; for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { int fx=find(edge[i].u),fy=find(edge[i].v); if(fx!=fy) { fa[fx]=fy; tot++; cnt+=edge[i].w; } if(tot==n-1)return cnt; } } int main() { n=read(); int x; for(int i=1;i<=n;i++) { x=read(); edge[++m].u=i; edge[m].v=n+1; edge[m].w=x; } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { x=read(); if(i<j) { edge[++m].u=i; edge[m].v=j; edge[m].w=x; } } } n++; sort(edge+1,edge+1+m); printf("%d\n",kruskal()); return 0; }