本题看似很难,实际上思路很是简单——若是你想通了。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; }