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

洛谷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 }
原文地址:https://www.cnblogs.com/third2333/p/7655173.html