演算法訓練 安慰奶牛 最小生成樹
阿新 • • 發佈:2019-02-18
5 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000。
思路:好久沒搞圖論了...最小生成樹都快忘了...
這道題只要理解了題意就是一個Kruskal模板題,因為題中要求的是到每一個點都要安慰所在頂點的奶牛,而且每天晚上都會在同一個牧場過夜,
這就說明我們選定一個點出發遍歷完這棵生成樹後還要返回樹根,也就是每個邊都走了兩邊,並且所在頂點的度(除起始點)為多少,該點就走幾遍.
由於每一個點也有權值,所以真正的權值為 2*邊的權值+邊所連兩個頂點的值
對於選哪一個點做為起始點:因為要求最短時間,所以我們起始點的奶牛的安慰時間要最少即可.
#include<bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; const int N=1e4+10; const int M=1e5+10; int C[N],n,p,sum; int pre[N]; struct node{ int u,v,w; }q[M]; int cmp(node x,node y) { return x.w<y.w; } void build() { for(int i=1;i<=n;i++) pre[i]=i; return ; } int find(int x) { if(x==pre[x]) return pre[x]; else { pre[x]=find(pre[x]); return pre[x]; } } int join(int x,int y) { int f1=find(x); int f2=find(y); if(f1!=f2) { pre[f2]=f1; return 1; } return 0; } void Kruskal() { int count=0; sum=0; for(int i=0;i<p;i++) { if(join(q[i].u,q[i].v)) { count++; sum+=q[i].w; } if(count==n-1) break; } return ; } int main() { int a,b,c; int ss=inf; scanf("%d%d",&n,&p); for(int i=1;i<=n;i++) { scanf("%d",&C[i]); ss=min(ss,C[i]); } for(int i=0;i<p;i++) { scanf("%d %d %d",&a,&b,&c); q[i].u=a; q[i].v=b; q[i].w=2*c+C[a]+C[b]; } sort(q,q+p,cmp); build(); Kruskal(); printf("%d\n",sum+ss); return 0; }