关于最小瓶颈树的详解

首先给出最小瓶颈树的定义:
树中的最大权值边 — 树中的最小权值边的值,是图G的各个生成树中最小的。
算法实现:
此类题要使用Kruskal算法进行求解,Kruskal算法详解:https://blog.csdn.net/luomingjun12315/article/details/47700237/
大体上是利用了Kruskal算法中的三条特性:
(1)、并查集的特性,如果祖先相同,则连接两点将会形成一个圈,破坏树形结构;
(2)、算法中对边枚举的方便性,通过不断对建造图所用边数的限制进行枚举;
(3)、易排序性(只是我单纯的这么感觉)。
知识点就这么多,下面给出两道非常经典易懂的例题(不要急,下面会给出总结):
题目链接: https://vjudge.net/problem/UVA-1395

#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
#include<cmath>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAX_V=200+10;
const int MAX_M= MAX_V*(MAX_V-1)/2+10;
int par[MAX_V],a,b,qur,V,M;

struct edge
{
    int u,v,cost;
    bool operator <(const edge &s)
    {
        return cost<s.cost;
    }
};

edge es[MAX_M];

int find(int x)
{
    return par[x]==x?x:(par[x]=find(par[x]));
}

int krusical()
{
    int res=INF;
    for(int i=0;i<M;i++)
    {
        int min_l=es[i].cost,cnt=V,max_l=0;
        for(int j=0;j<=V;j++) par[j]=j;
        for(int j=i;j<M;j++)
        {
            int fu=find(es[j].u);
            int fv=find(es[j].v);
            int fcost=es[j].cost;
            if(fu!=fv)
            {
                max_l=fcost;
                par[fu]=fv;
                cnt--;//生成树的边数=V-1;
            }
        }
        if(cnt==1)
        res=min(res,max_l-min_l);
    }
    if(res==INF) return -1;//判断是否构成图
    return res;
}


int main()
{
    while(scanf("%d %d",&V,&M)==2)
    {
        if(V==0&&M==0) break;
        for(int i=0; i<M; i++)  scanf("%d %d %d",&es[i].u,&es[i].v,&es[i].cost);
        sort(es,es+M);
        printf("%d\n",krusical());
    }
    return 0;
}

题目链接:https://vjudge.net/problem/UVA-10457

#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
#include<cmath>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAX_V=200+10;
const int MAX_M=1000+10;
int par[MAX_V],a,b,qur,V,M;

struct edge
{
    int u,v,cost;
    bool operator <(const edge &s)
    {
        return cost<s.cost;
    }
};

edge es[MAX_M];

int find(int x)
{
    return par[x]==x?x:(par[x]=find(par[x]));
}

int krusical(int s,int t)
{
    int res=INF;
    for(int i=0;i<M;i++)
    {
        int max_l=es[i].cost;
        for(int j=0;j<=V;j++) par[j]=j;
        for(int j=i;j<M;j++)
        {
            int fu=find(es[j].u);
            int fv=find(es[j].v);
            int fcost=es[j].cost;
            if(fu!=fv) par[fu]=fv;
            if(find(s)==find(t))//说明已经连接为通路
            {
                //cout<<"输出过程之  "<<fcost<<"       "<<max_l<<endl;
                res=min(res,fcost-max_l);
                //cout<<"输出中间值  "<<res<<endl;
                break;
            }
        }
    }
    return res;
}


int main(){
    while(scanf("%d %d",&V,&M)==2)
    {
        for(int i=0;i<M;i++)  scanf("%d %d %d",&es[i].u,&es[i].v,&es[i].cost);
        sort(es,es+M);
        scanf("%d %d",&a,&b);
        scanf("%d",&qur);
        while(qur--)
        {
            int s,t; scanf("%d %d",&s,&t);
            //cout<<"输出中间值 "<<endl;
            printf("%d\n",a+b+krusical(s,t));
        }
    }
    return 0;
}

简单总结一下,其实这两道题,题意都差不多,只是个别的细节上会有些差别,但是根据这两道题大致上可以归纳出最小瓶颈树的解题套路:
(1)、完整的Kruskal;
(2)、算法內的全部枚举;
至于结束条件,以及main函数中的写法,根据题意改改就OK;
以上为个人理解,有不对的欢迎在评论区留言~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值