最小生成数 There is No Alternative

本文介绍了一种使用最小生成树算法确定图中哪些边为关键边的方法。通过两次运行最小生成树算法并对比结果,可以判断每条边是否为最小生成树所必需。文章提供了完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送们 :题目连接
思路:定位就是一个最小生成数的水题,先跑一遍最小生成树,找出最小的花费,顺便把最小生成树的边记录下来,然后删边,看再跑最小生成树,看是否能得到相同的花费,如果能的话,则是这条边是可替代的,否则则是不可替代的。
有趣的是,排序再结构体里面重载比写cmp函数快的多。写cmp超时,而重载运算符就能过了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<stack>
#define eps 1e-7
#define INF 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxe = 5e4+4;
const int maxn = 500+5;
struct edge{
    int u,v,cost,id;
    bool operator < (const edge &a){
        return cost < a.cost;
    }
};
edge es[maxe];
edge es1[maxe];
vector<int> vec;
int pre[maxn];
int V,E;
void init(){
    for(int i=1;i<=V;i++)pre[i] = i;
}
int find(int x){
    return x == pre[x]?x:pre[x] = find(pre[x]);
}
void unit(int x,int y){
    int fx = find(x),fy = find(y);
    if(fx!=fy){
        pre[fx] = fy;
    }
}
bool same(int x,int y){
    int fx = find(x),fy = find(y);
    return fx == fy;
}
int kruskal(bool flag){
    init();
    int sum = 0;
    sort(es,es+E);
    for(int i=0;i<E;i++){
        edge e = es[i];
        if(!same(e.u,e.v)){
            unit(e.u,e.v);
            sum+=e.cost;
            if(flag){
                vec.push_back(e.id);
            }
        }
    }
    return sum;
}
void init1(){
    for(int j=0;j<E;j++){
        es[j].u = es1[j].u;
        es[j].v = es1[j].v;
        es[j].cost = es1[j].cost;
        es[j].id = es1[j].id;
    }
}
void solve(){
    vec.clear();
    init1();
    int min_tree = kruskal(true);
    int ans = 0,sum = 0;
    for(int i=0;i<vec.size();i++){
        init1();
        es[vec[i]].cost = INF;
        int tree = kruskal(false);
        if(tree != min_tree){
            ans++;
            sum+=es1[vec[i]].cost;
        }
    }
    printf("%d %d\n",ans,sum);
}
int main()
{
    while(~scanf("%d%d",&V,&E)){
        for(int i=0;i<E;i++){
            int s,t,cost;
            scanf("%d %d %d",&s,&t,&cost);
            es1[i].u = s;
            es1[i].v = t;
            es1[i].cost = cost;
            es1[i].id = i;
        }
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值