讲解 算法训练 安慰奶牛

首先谈谈这道题的基本思路吧,题目中谈到要将P条道路尽可能的去减少,并保证个点之间是可达的,同时要求其最小时间。

很明显的去告诉我们,用最小生成树算法。

最小生成树算法有两种,

1.克鲁斯卡尔算法 2.prim算法

注意

排序用sort函数。(不要用冒泡排序)。

如果用冒泡排序。会一直显示超时的问题

sort函数(优化后的快速排序)。会根据数据量去选择用何种排序方法(快速排序,或堆排序)

很多向我一样的萌新会去使用冒泡排序,但sort函数既简洁又方便。

技巧:

因为他最后会在每个结点处休息的。所以结点的时间也会去算的。

每个边会走两次(去的时候一次,回来的时候一次,)也就是每条边所花费的时间是

(走边的权的时间*2+去的那个结点安慰奶牛的时间+回来的那个结点安慰奶牛的时间)

由于不管我们怎么走,选取哪些边,从中间走,或从两头走,平均每条边花费的时间都是

上面的

所以我们直接将   边的权=(走边的权的时间*2+去的那个结点安慰奶牛的时间+回来的那个结点安慰奶牛的时间);

最后再进行克鲁斯卡尔算法,求最小生成树的值。

最后值+最小结点,因为有个结点会多走一次(细读题意)。所以我们直接在最小的结点开始走。

(因为一定要连接所有结点),所以否定了这个结点可能走不到的问题。

如果此题

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct bian
{
    int from;//起点
    int to;//终点
    int quan;//权值
};
int root (int a[],int x)//寻根算法
{
    while(a[x]!=x)
    {
        x=a[x];
    }
    return x;
}
bool cmp(bian b1,bian b2)
{
    return b1.quan<b2.quan;
}
int main ()
{
    int sum=0;//记录所有的时间
    int n,p;//结点数与边数
    cin>>n;
    cin>>p;
    int a[n+1];//记录所有点的父亲(双亲表示法)
    bian b[p+1];//所有边
    int i;
    int m[n+1];
    int min=10001;
    for(i=1;i<=n;i++)
    {
        cin>>m[i];
        if(m[i]<=min)
        {
            min=m[i];
        }
    }
    for(i=1;i<=p;i++)
    {
        cin>>b[i].from>>b[i].to>>b[i].quan;
        b[i].quan=b[i].quan*2+m[b[i].to]+m[b[i].from];
    }
    sort(b+1,b+p+1,cmp);
    for(i=1;i<=n;i++)
    {
        a[i]=i;//每个人都是自己的父亲
    }
    int j;
    bian t;

    int k=0;//记录kustral算法收纳的边数
    int zhong1;
    int zhong2;
    for(i=1;i<=p;i++)
    {
        zhong1=root(a,b[i].from);
        zhong2=root(a,b[i].to);
        if(zhong1!=zhong2)
        {
            a[zhong1]=zhong2;
            sum+=b[i].quan;
            k++;
        }
        if(k==n-1)
        {
            break;
        }
    }
    cout<<sum+min;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值