洛谷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 }