1. 程式人生 > >洛谷P2840 [USACO20DEC]Moocast(gold)奶牛廣播-金

洛谷P2840 [USACO20DEC]Moocast(gold)奶牛廣播-金

for 出發 mooc str mes style 生成樹 方法 一個

洛谷P2840 [USACO20DEC]Moocast(gold)奶牛廣播-金
就是最小生成樹的模板題

蒟蒻我在這這裏使用的就是最好寫的Kruskal算法

(做這道題之前,最好先去把‘最小生成樹模板’這道題先過了)

但是,從哪裏看出這是最小生成樹是一個值得一提的問題(或者說如何構圖)

我的方法:以A~B為例子,AB這條邊的邊權就等於A點的值+B點的值+2*AB(因為這條路要來回走,共兩遍)

然後再找點的值最小的一個點,作為出發點,就可以愉快地跑Kruskal了

下面是拙劣的代碼

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4
using namespace std; 5 const int N=10005,M=100005; 6 int p[N],f[N]; 7 struct Node{ 8 int u,v,w;//u->v的邊,權值為w 9 }a[M]; 10 int find(int x){//並查集找祖宗(劃掉)祖先 11 return f[x]==x?x:f[x]=find(f[x]); 12 } 13 bool cmp(Node a,Node b){ 14 return a.w<b.w; 15 } 16 inline int mn(int a,int b){ 17 return
a<b?a:b; 18 } 19 int main (){ 20 int n,m,ans=1<<30; 21 scanf ("%d%d",&n,&m); 22 for (int i=1;i<=n;i++) scanf ("%d",&p[i]),ans=mn(ans,p[i]),f[i]=i;//註意,並查集中每個元素初始時自己都是自己的祖宗,所以f[i]=i 23 for (int i=1;i<=m;i++){ 24 scanf ("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
25 a[i].w*=2; 26 a[i].w+=p[a[i].u]+p[a[i].v];//上面說的構圖方法 27 } 28 sort(a+1,a+m+1,cmp); 29 for (int i=1;i<=m;i++){//跑最小生成樹 30 int x=find(a[i].u),y=find(a[i].v); 31 if (x!=y){//如果兩個的祖宗不同(就是不在一個集合內) 32 ans+=a[i].w;//這條邊必須選 33 f[x]=y;//合並兩個集合 34 } 35 } 36 printf ("%d",ans); 37 return 0; 38 }

洛谷P2840 [USACO20DEC]Moocast(gold)奶牛廣播-金