[USACO08NOV]安慰奶牛Cheering up the Cow

这个题一看就是最小生成树,但是这题关键是确定边权。

首先为了安慰奶牛,一定要遍历每个奶牛并且回到起点,所以每条边会被经过两次,而为了通过这条边必须和两端点奶牛谈话,因此要再加上两端点的c值。综上(i,j)边权为l(i,j)  * 2 + c_i + c_j。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 10010
#define M 10000000
using namespace std;
int n,m;
struct qwq
{
    int x,y,val;
    bool operator < (const qwq &a) const
    {
        return val < a.val;
    }
}e[M];
int fa[N],siz[N];
int find(int x)
{
    if(fa[x] != x) fa[x] = find(fa[x]);
    return fa[x];
}
void merge(int x,int y)
{
    if(siz[x] > siz[y]) swap(x,y); 
    siz[y] += siz[x];
    fa[x] = y;
    return;
}
int kruskal()
{
    sort(e + 1,e + 1 + m);
    int tot = 0,ans = 0;    
    for(int i = 1;i <= m;i++)
    {
        int x = find(e[i].x),y = find(e[i].y);
        if(x != y)
        {
            merge(x,y);
            ans += e[i].val;
            tot++;
        }
        if(tot == n - 1) break;
    }
    return ans;
}
int c[N];
using namespace std;
int main()
{
    scanf("%d %d",&n,&m);
    int minn = 1000000;
    for(int i = 1;i <= n;i++) 
    {
        scanf("%d",&c[i]);
        minn = min(c[i],minn);
        fa[i] = i;
        siz[i] = 1;
    }
    for(int i = 1;i <= m;i++) 
    {
        scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].val);
        e[i].val = (e[i].val << 1) + c[e[i].x] + c[e[i].y];
    }
    printf("%d\n",kruskal() + minn);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lijilai-oi/p/10939755.html