安慰奶牛 蓝桥真题

 

 

这个题关键在于怎么处理这些点需要重复到达的问题 题目要求最后只剩一个树图 即只留(n-1)条边 我们把每条边的边权乘二 再加上左右两节点的点权 作为新的边权 然后套克鲁斯卡尔 最后加上一个最小的点权

 

 

1. 边权乘二

那么对于每一条边edge[i] 它都连接了以左节点edge[i].u为根的子树(左树)和以右节点edge[i].v为根的子树(右树) 而题目要求最后必须回到出发点 那么假设我们出发点在左树 现在要经过edge[i]去遍历右树上的节点 去时走了一次edge[i] 因为要回到出发点 所以又走了一次edge[i] 所以这个一来一回是必不可少的 又因为我们返回时再次经过edge[i]时 肯定已经把右树节点都处理完毕(不然你回来干什么。。) 所以每条边必走两次且只走两次

2. 加上左右两节点的点权

设节点p 其邻接边有 a b c d

如果我们走a来到了p(一次访问) 现在要通过b c d去遍历其下的子树 因为要回到出发点 所以在回程时必经a各一次(b c d共三次)

所以每个节点有多少邻接点 即度为多少 那它就要被经过几次

可这些度是谁提供的呢 当然是边啊 无向图中每条边会为左右两个节点各贡献一个度 所以在这里我们就可以把这些点权附加到边权上了 这样就可以处理了

3. 加上一个最小的点权

 

 

出发时还要安慰出发点的那头牛 等于经过了一次出发点 但我们是突然出现在出发点的 无法在出发点的度上体现出来 所以必须单独考虑

不管我们把谁作为出发点 1 2条是不变的 所以哪个点权值小就把谁作为出发点

 

 

 

 

好啰嗦。。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 0x3f3f3f3f3f3f3f3f

struct node
{
    int u;
    int v;
    ll w;
};

node edge[100010];
ll val[10010];
int f[10010];
int n,m;

bool cmp(node n1,node n2)
{
    return n1.w<n2.w;
}

int getf(int p)
{
    if(f[p]==p) return p;
    else
    {
        f[p]=getf(f[p]);
        return f[p];
    }
}

bool unite(int u,int v)
{
    int fu,fv;
    fu=getf(u);
    fv=getf(v);
    if(fu!=fv)
    {
        f[fv]=fu;
        return true;
    }
    else return false;
}

int main()
{
    ll sum,minn;
    int i,cnt;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&val[i]);
    }
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%lld",&edge[i].u,&edge[i].v,&edge[i].w);
        edge[i].w=2*edge[i].w+val[edge[i].u]+val[edge[i].v];
    }
    for(i=1;i<=n;i++)
    {
        f[i]=i;
    }
    sort(edge+1,edge+m+1,cmp);
    sum=0,cnt=0;
    for(i=1;i<=m;i++)
    {
        if(unite(edge[i].u,edge[i].v))
        {
            sum+=edge[i].w,cnt++;
        }
        if(cnt==n-1) break;
    }
    minn=N;
    for(i=1;i<=n;i++)
    {
        minn=min(minn,val[i]);
    }
    printf("%lld\n",sum+minn);
    return 0;
}

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值