• AcWing 356. 次小生成树


    AcWing 356. 次小生成树

    一道蛮经典的题目,随手记录下。

    原题链接:https://www.acwing.com/problem/content/description/358/

    题目描述:

    给定一张 N 个点 M 条边的无向图,求无向图的严格次小生成树。

    设最小生成树的边权之和为sum,严格次小生成树就是指边权之和大于sum的生成树中最小的一个。

    注意本题所求的次小生成树是严格次小的

    题解:先用kruskal求出给定图的最小生成树,再枚举没有被选上的边,假设把这条边加上,就会形成一个环,只要把环中的最大边删去,就可以得到一颗新的树,枚举后得到最小的新树就是次小生成树。这里注意

    因为是严格次小所以我们需要判断每个环中的最大边是否和新加入的边一样,所以还需要维护一个次大边。我们用lca倍增来维护就可以使时间复杂度降到nlogn

    #include <stdio.h>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <map> 
    #include <stack>
    #include <sstream>
    #include <set>
    #pragma GCC optimize(2)
    
    //#define int long long
    #define rush() int T;scanf("%d",&T);for(int Ti=1;Ti<=T;++Ti)
    #define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    #define mm(i,v) memset(i,v,sizeof i);
    #define mp(a, b) make_pair(a, b)
    #define pi acos(-1)
    #define fi first
    #define se second
    //你冷静一点,确认思路再敲!!! 
    
    using namespace std;
    typedef long long ll;
    typedef pair<int, int > PII;
    priority_queue< PII, vector<PII>, greater<PII> > que;
    stringstream ssin; //  ssin << string   while ( ssin >> int)
    
    const int N = 1e5 + 5, M = 6e5 + 5, mod = 1e9 + 7, INF = 0x3f3f3f3f;
    int n, m, t, anc;
    int e[M], ne[M], h[M], w[M], idx;
    int fa[N][20], d1[N][20], d2[N][20], depth[N];
    int p[N];
    
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    
    void add(int a, int b, int c) {
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    
    struct Edge
    {
        int a, b, w;
        bool vis;
        bool operator< (const Edge &t) {
            return w < t.w;
        }
    }edge[M];
    
    int find(int x) {
        if (p[x] != x) return p[x] = find(p[x]);
        else return p[x];
    }
    
    ll kruskal() {
        ll res = 0;
        for (int i = 1; i <= n; ++i) p[i] = i;
        sort(edge + 1, edge + 1 + m);
        for (int i = 1; i <= m; ++i) {
            int a = edge[i].a, b = edge[i].b, c = edge[i].w;
            int pa = find(a), pb = find(b);
            if (pa == pb) continue;
            p[pa] = pb;
            edge[i].vis = 1;
            res += c;
        }
        return res;
    }
    
    void build() {
        mm(h, -1);
        for (int i = 1; i <= m; ++i) {
            if (!edge[i].vis) continue;
            int a = edge[i].a, b = edge[i].b, c = edge[i].w;
            add(a, b, c);
            add(b, a, c);
        }
    }
    
    void bfs() {
        mm(depth, 0x3f);
        queue<int>q;
        q.push(1);
        depth[0] = 0; depth[1] = 1;
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = h[u]; ~i; i = ne[i]) {
                int v = e[i], z = w[i];
                if (depth[v] > depth[u] + 1) {
                    depth[v] = depth[u] + 1;
                    fa[v][0] = u;
                    d1[v][0] = z;
                    d2[v][0] = -INF;
                    q.push(v);
                    for (int k = 1; k <= t; ++k) {
                        anc = fa[v][k - 1];
                        fa[v][k] = fa[anc][k - 1];
                        
                        int dis[4] = {d1[v][k - 1], d1[anc][k - 1], d2[v][k - 1], d2[anc][k - 1]};
                        d1[v][k] = d2[v][k] = -INF;
                        for (int j = 0; j < 4; ++j) {
                            if (dis[j] > d1[v][k]) {
                                d2[v][k] = d1[v][k];
                                d1[v][k] = dis[j];
                            } else if (dis[j] != d1[v][k]){
                                d2[v][k] = max(d2[v][k], dis[j]);
                            }
                        }
                    }
                }
            }
        }
    }
    
    
    int lca(int a, int b, int c) {
        int dd[N + N], cnt = 0;
        if (depth[a] < depth[b]) swap(a, b);
        for (int k = t; k >= 0; --k) {
            if (depth[fa[a][k]] >= depth[b]) {
                dd[++cnt] = d1[a][k];
                dd[++cnt] = d2[a][k];
                a = fa[a][k];
            }
        }
        if (a != b) {
            for (int k = t; k >= 0; --k) {
                if (fa[a][k] != fa[b][k]) {
                    dd[++cnt] = d1[a][k];
                    dd[++cnt] = d2[a][k];
                    dd[++cnt] = d1[b][k];
                    dd[++cnt] = d2[b][k];
                    a = fa[a][k];
                    b = fa[b][k];
                }
            }
            dd[++cnt] = d1[a][0];
            dd[++cnt] = d1[b][0];
        }
    
        int dis1 = -INF, dis2 = -INF; // 最大和次大
        for (int i = 1; i <= cnt; ++i) {
            int d = dd[i];
            if (d > dis1) {
                dis2 = dis1;
                dis1 = d;
            } else if (d != dis1) {
                dis2 = max(dis2, d);
            }
        }
        if (c > dis1) return c - dis1;
        if (c > dis2) return c - dis2;
        return INF;
    }
    
    int main()
    {
        // freopen("in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取
        // freopen("out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中
        n = read(); m = read();
        t = log2(N) + 1;
        for (int i = 1; i <= m; ++i) {
            int a, b, c;
            a = read(); b = read(); c = read();
            edge[i] = {a, b, c};
        }
        ll res = kruskal();
        // cout << res << '
    ';
        build();
        bfs();
        ll ans = 1e18;
        for (int i = 1; i <= m; ++i) {
            if (edge[i].vis) continue;
            int a = edge[i].a, b = edge[i].b, c = edge[i].w;
            ans = min(ans, res + lca(a, b, c));
        }
        cout << ans << '
    ';
        // system("pause");
    }
  • 相关阅读:
    正确使用c语言中的头文件
    用Python玩转大数据-入门阶段
    Python基础知识进阶(五---2)----程序基本结构、简单分支、异常处理、三大实例分析、基本循环结构、通用循环构造方法、死循环嵌套循环、布尔表达式
    Python基础知识进阶(五---1)----程序基本结构、简单分支、异常处理、三大实例分析、基本循环结构、通用循环构造方法、死循环嵌套循环、布尔表达式
    Python小程序练习(7个) 2017年9月28日---告诉自己多东西练习,而不是去空想
    python基础知识进阶(四) Python语言的math库和random库和实例
    python基础知识进阶(二) Python语言的数据类型
    python基础知识进阶之路(一)
    今天2017.5.23 开始一个web端网上商城项目的开发
    Lambda表达式(转载)
  • 原文地址:https://www.cnblogs.com/mwh123/p/13493067.html
Copyright © 2020-2023  润新知