1. 程式人生 > 實用技巧 >b_lg_按位奶牛(預處理點權和邊權)

b_lg_按位奶牛(預處理點權和邊權)

john走訪完所有的奶牛之後,還要回到他的出發地。
每次路過牧場i的時候,john必須花Ci的時間和奶牛交談,即使之前已經做過工作
請你計算一下,約翰要拆除哪些道路,才能讓談話(忽悠)奶牛的時間變得最少?

知道是MST,但回程難以模擬,故直接將邊權設為:邊權*2+兩個端點的點權
注:由於和起點相連的邊一開始就被加到一個連通塊中,假如起點出度為2,則起點需要被經過3次才對,但kruskal只會算兩次,故還要加上最小的點權(起點的點權)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5, M=1e6+5;
int n,m,fa[N],c[N];
struct edge {
    int u,v,w;
}e[M];
int find(int u) {return fa[u]==u ? u : fa[u]=find(fa[u]);}
int kruskal() {
    for (int i=1; i<=n; i++) fa[i]=i;
    sort(e,e+m,[&](edge a, edge b){return a.w<b.w;});
    int ans=0;
    for (int i=0; i<m; i++) {
        int fu=find(e[i].u), fv=find(e[i].v);
        if (fu!=fv) {
            fa[fu]=fv;
            ans+=e[i].w;
        }
    }
    return ans;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m;
    for (int i=1; i<=n; i++) cin>>c[i];
    for (int i=0; i<m; i++) cin>>e[i].u>>e[i].v>>e[i].w, e[i].w=2*e[i].w+c[e[i].u]+c[e[i].v];
    cout<<*min_element(c+1,c+n+1)+kruskal();
    return 0;
}

我的疑惑:kruskal不是按照邊權+點權排序的嗎?那約束有兩個啊,萬一和點權很小的點連線的邊權很大(那就不是起點了啊),那這個額外加不就錯了嗎