[BZOJ1232][Usaco2008Nov]安慰奶牛cheer(贪心+kruskal)

来源:互联网 发布:java应用程序开发实例 编辑:程序博客网 时间:2024/06/04 23:28

题目描述

传送门

题解

将每一条边的边权记为原边权*2+两个点的权值,然后做最小生成树。
但是发现这样的话起点会少访问一次。
起点无论是哪个都是这n个点之中的嘛。。那么选一个最小的就好啦。

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define N 100005#define inf 2100000000int n,m,x,y,z,Min,ans,cnt;int val[N],f[N];struct hp{int x,y,z;}e[N];int cmp(hp a,hp b){    return a.z<b.z;}int find(int x){    if (x==f[x]) return x;    f[x]=find(f[x]);    return f[x];}int main(){    scanf("%d%d",&n,&m);Min=inf;    for (int i=1;i<=n;++i) scanf("%d",&val[i]),Min=min(Min,val[i]);    for (int i=1;i<=m;++i)    {        scanf("%d%d%d",&x,&y,&z);        e[i].x=x,e[i].y=y,e[i].z=z*2+val[x]+val[y];    }    sort(e+1,e+m+1,cmp);    for (int i=1;i<=n;++i) f[i]=i;    for (int i=1;i<=m;++i)    {        int f1=find(e[i].x),f2=find(e[i].y);        if (f1!=f2)        {            f[f1]=f2;ans+=e[i].z;            cnt++;            if (cnt==n-1) break;        }    }    printf("%d\n",ans+Min);}
0 0