可以發現每個點經過次數恰好等於這個點的度數,所以把點權下放邊權,跑最小生成樹,原來邊權乘二在加上兩端點權,答案再加一遍起點最小點權
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=10010; const int maxm=100010; int n,m; ll ans; struct node{ int u,v,w,nxt; bool operator <(const node&a)const{ return w<a.w; } }e[maxm*2]; int head[maxn],cnt,w[maxn]; int fa[maxn]; int find(int x){ while(x!=fa[x])x=fa[x]=fa[fa[x]];return x; } void add(int u,int v,int ww){ e[++cnt].v=v;e[cnt].u=u;e[cnt].w=ww;e[cnt].nxt=head[u];head[u]=cnt; e[cnt].w=(e[cnt].w*2)+w[u]+w[v]; } void kruskal(){ for(int i=1;i<=n;i++)fa[i]=i; sort(e+1,e+1+cnt); for(int i=1;i<=cnt;i++){ int x=find(e[i].u),y=find(e[i].v),z=e[i].w; if(x==y)continue; fa[x]=y; ans+=z; } } int main(){ scanf("%d%d",&n,&m);int minn=0x7fffffff; for(int i=1;i<=n;i++)scanf("%d",&w[i]),minn=min(minn,w[i]); for(int i=1,u,v,w;i<=m;i++){ scanf("%d%d%d",&u,&v,&w); add(u,v,w); // add(v,u,w); } kruskal(); printf("%lld",ans+minn); }