[題解](最小生成樹)luogu_P2916安慰奶牛

可以發現每個點經過次數恰好等於這個點的度數,所以把點權下放邊權,跑最小生成樹,原來邊權乘二在加上兩端點權,答案再加一遍起點最小點權

#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);
}

 

posted @ 2019-04-30 13:19  羊肉汤泡煎饼  阅读(114)  评论(0编辑  收藏  举报