vijos1070_ on the method of finding the next smallest spanning tree

(One day, there was a cute scene on xzz)
jzz: DG, will you ask for the minimum spanning tree?

DG: Yes!
jzz: What about the small spanning tree?
DG: Well... -_-|| won't —— enumerate and then brute force?
jzz: Qi, O(nmlogm) blew up early.
DG: How exactly?
jzz: Ask the DL, maybe he'll tell you when he's in a good mood.
DL: So the question is, how to use the O(n²+mlogm) method to find the next smallest spanning tree?


    First of all, we must know how to find the minimum spanning tree, what kruskal, prim, a lot of questions can be solved casually, right?
    When facing the sub-small spanning tree problem, you can choose to enumerate each edge in the original MST to delete, and then run the MST algorithm (of course, there may be a better brute force method, which will not be described in detail here), so that As a result, the complexity reaches the level of O(nmlogm), and smaller data is also possible. However, if we want to pursue better, we need to use another method.
A concept: the minimum bottleneck path
    finds a path connecting two points in an undirected graph, so that the edge with the largest weight on the path is as small as possible, then this path is called the minimum bottleneck path.
    The calculation method is also very simple. If the MST is constructed in the original graph, the path between two points on the MST is the minimum bottleneck path. The proof is also very simple, as long as the largest edge is maintained to be the smallest, all the previous edges can be sorted, and then added in turn until the two points are connected. Look at the previous operation, isn't it kruskal?
Specific process:
    After getting familiar with the above concepts, the next process is very simple. This time, we enumerate which edge to add, add the weight of this edge, and then subtract the maximum edge weight on the minimum bottleneck path of the two points connected by this edge to get a new spanning tree. This is the process of "edge exchange". After all, the next smallest spanning tree is obtained by deleting an edge and adding a new edge to the minimum spanning tree. This is easy to prove. So, we enumerate the newly added edges in O(m) time, then update the answer in O(1) time, and finally output. The previous complexity of MST is O(mlogm), the maximum weight on the minimum bottleneck path is O(n²), and the total complexity is O(n²+mlogm).

Title: https://vijos.org/p/1070

#include <cstdio>
#include <algorithm>
#define N 500 + 10
#define M 150000
#define INF 1000000000

using namespace std;

struct line
{
    int l, r, w;
}c[M];
struct edge
{
    int fr, to, w, next;
}e[2*N];
int n, m, num, now, ans1, ans2 = INF;
int fa[N], p[N], d[N][N], used[M];
bool cmp(line a, line b)
{
    return a.w < b.w;
}
int find(int x)
{
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}
int read()
{
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    int x = 0;
    while(c >= '0' && c <= '9')
    {
        x = 10*x + c - '0';
        c = getchar();
    }
    return x;
}
void add(int x, int y, int z)
{
    e[++num].fr = x;
    e[num].to = y;
    e[num].w = z;
    e[num].next = p[x];
    p[x] = num;
}
void init()
{
    n = read(), m = read();
    for (int i = 1; i <= m; ++i)
    {
        c[i].l = read();
        c[i].r = read();
        c[i].w = read();
    }
}
void kruskal()
{
    for (int i = 1; i <= n; ++i)
    fa[i] = i;
    sort(c+1, c+m+1, cmp);
    for (int i = 1; i <= m; ++i)
    {
        int fl = find(c[i].l), fr = find(c[i].r);
        if (fl != fr)
        {
            used[i] = 1;
            fa[fl] = fr;
            ans1 += c[i].w;
            add(c[i].l, c[i].r, c[i].w);
            add(c[i].r, c[i].l, c[i].w);
            if (n - 1 == num / 2) return;
        }
    }
}//克鲁斯卡尔
void dfs_mini(int x, int fr, int maxs)
{
    d[now][x] = maxs;
    for (int i = p[x]; i; i = e[i].next)
    {
        int k = e[i].to;
        if (k != fr) dfs_mini(k, x, max(maxs, e[i].w));
    }
}//求最小瓶颈路上最大权值
void deal()
{
    kruskal();
    if (n - 1 == num / 2) printf("Cost: %d\n", ans1);
    else
    {
        printf("Cost: -1\n");
        printf("Cost: -1\n");
        return;
    }
    for (now = 1; now <= n; ++now)
    dfs_mini(now, 0, 0);
    for (int i = 1; i <= m; ++i)
    if (!used[i] && ans1 - d[c[i].l][c[i].r] + c[i].w < ans2)
    ans2 = ans1 - d[c[i].l][c[i].r] + c[i].w;//枚举并更新
    if (ans2 != INF) printf("Cost: %d\n", ans2);
    else printf("Cost: -1\n");
}
int main()
{
    init();
    deal();
    return 0;
}


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326291756&siteId=291194637