📌  相关文章
📜  求最小生成树的权重

📅  最后修改于: 2021-10-25 03:23:33             🧑  作者: Mango

给定一个具有 N 个节点M 个边的连通无向加权图。任务是执行给定的查询并找到最小生成树的权重。查询分为三种类型:

  1. query(1) -> 求最小生成树的权重。
  2. query(2, x, y) -> 将节点 xy之间的边的权重更改为0
  3. query(3, x, y) -> 将节点 xy之间的边的权重恢复为其原始权重

例子:

方法:让我们在执行任何查询之前先计算初始图的 MST,并让 T 为这个 MST。关键的观察是,在处理查询的任何时候,当前图的 MST 的权重可以通过在此时权重为零的边和 T 的边上运行 Kruskal 算法来计算。因此,保持权重为零的边在一个数据结构,在查询类型 2 和类型 3 后计算最小生成树的权重。
下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
#define N 2005
 
// To store vertices, edges
// and the required answer
int n, m, ans;
 
// To store parent and rank
int par[N], Rank[N];
 
// To store edges and the edges in MST
vector > > edges, mst;
 
// To store the edges with weight zero
queue > zeros;
 
// Function for initialize
void initialize()
{
    for (int i = 0; i <= n; i++) {
        par[i] = i;
        Rank[i] = 0;
    }
}
 
// Function to add edges
void Add_edge(int u, int v, int weight)
{
    edges.push_back({ weight, { u, v } });
}
 
// Utility function to find set of an element i
// (uses path compression technique)
int find(int x)
{
    if (par[x] != x)
        par[x] = find(par[x]);
 
    return par[x];
}
 
// Function that performs union of two sets x and y
// (uses union by rank)
void Union(int x, int y)
{
    int xroot = find(x);
    int yroot = find(y);
 
    if (Rank[xroot] < Rank[yroot])
        par[xroot] = yroot;
    else if (Rank[xroot] > Rank[yroot])
        par[yroot] = xroot;
    else {
        par[yroot] = xroot;
        Rank[xroot]++;
    }
}
 
// Function to compute minimum spanning tree
void compute_MST()
{
    // Sort edges in increasing order of weight
    sort(edges.begin(), edges.end());
 
    // Go through all the edges
    for (int i = 0; i < m; i++) {
        int u = find(edges[i].second.first);
        int v = find(edges[i].second.second);
 
        if (u == v)
            continue;
 
        // Build minimum spanning tree
        // and store minimum cost
        mst.push_back(edges[i]);
        ans += edges[i].first;
        Union(u, v);
    }
}
 
// Function to find the cost of minimum
// spanning tree
void Modified_Kruskal(pair x)
{
    initialize();
 
    // Make answer zero
    ans = 0;
    int sz = zeros.size();
 
    // Keep the edges which only have zero weights
    // and remove all the other edges
    for (int i = 0; i < sz; i++) {
        pair Front = zeros.front();
        zeros.pop();
 
        if (Front.first == x.first
            and Front.second == x.second)
            continue;
 
        // Make union between the vertices of
        // edges which have weight zero and keep
        // them in queue
        Union(Front.first, Front.second);
        zeros.push(Front);
    }
 
    // Find the cost of the minimum spanning tree
    for (int i = 0; i < mst.size(); i++) {
        int u = find(mst[i].second.first);
        int v = find(mst[i].second.second);
 
        if (u == v)
            continue;
 
        ans += mst[i].first;
        Union(u, v);
    }
}
 
// Function to handle different queries
void query(int type, int u = 0, int v = 0)
{
 
    // Update edge weight to 0
    if (type == 2) {
        // push edge in zeros
        zeros.push({ u, v });
        Modified_Kruskal({ -1, -1 });
    }
 
    // Restore edge weight to original value
    else if (type == 3) {
        // push edge in zeros
        zeros.push({ u, v });
        Modified_Kruskal({ u, v });
    }
    else
        cout << ans << endl;
}
 
// Driver code
int main()
{
 
    // Number of nodes and edges
    n = 4, m = 4;
    initialize();
 
    // Add edges
    Add_edge(1, 2, 1);
    Add_edge(2, 3, 1);
    Add_edge(3, 4, 1);
    Add_edge(4, 1, 1);
 
    // Build the minimum spanning tree
    compute_MST();
 
    // Execute queries
    query(2, 1, 2);
    query(1);
    query(3, 1, 2);
    query(1);
 
    return 0;
}


Python3
# Python3 implementation of the approach
from collections import deque
 
N = 2005
 
# To store vertices, edges
# and the required answer
n, m, ans = 0, 0, 0
 
# To store parent and rank
par = [0] * N
Rank = [0] * N
 
# To store edges and the edges in MST
edges, mst = [], []
 
# To store the edges with weight zero
zeroes = deque()
 
# Function for initialize
def initialize():
    for i in range(n + 1):
        par[i] = i
        Rank[i] = 0
 
# Function to add edges
def add_edge(u: int, v: int, weight: int):
    edges.append((weight, (u, v)))
 
# Utility function to find set of an element i
# (uses path compression technique)
def find(x: int) -> int:
    if par[x] != x:
        par[x] = find(par[x])
    return par[x]
 
# Function that performs union of two sets x and y
# (uses union by rank)
def union(x: int, y: int):
    xroot = find(x)
    yroot = find(y)
 
    if Rank[xroot] < Rank[yroot]:
        par[xroot] = yroot
    elif Rank[xroot] > Rank[yroot]:
        par[yroot] = xroot
    else:
        par[yroot] = xroot
        Rank[xroot] += 1
 
# Function to compute minimum spanning tree
def compute_MST():
    global ans
 
    # Sort edges in increasing order of weight
    edges.sort()
 
    # Go through all the edges
    for i in range(m):
        u = find(edges[i][1][0])
        v = find(edges[i][1][1])
 
        if u == v:
            continue
 
        # Build minimum spanning tree
        # and store minimum cost
        mst.append(edges[i])
        ans += edges[i][0]
        union(u, v)
 
# Function to find the cost of minimum
# spanning tree
def modified_kruskal(x):
    global ans
    initialize()
 
    # Make answer zero
    ans = 0
    sz = len(zeroes)
 
    # Keep the edges which only have zero weights
    # and remove all the other edges
    for i in range(sz):
        front = zeroes[0]
        zeroes.popleft()
 
        if front[0] == x[0] and front[1] == x[1]:
            continue
 
        # Make union between the vertices of
        # edges which have weight zero and keep
        # them in queue
        union(front[0], front[1])
        zeroes.append(front)
 
    # Find the cost of the minimum spanning tree
    for i in range(len(mst)):
        u = find(mst[i][1][0])
        v = find(mst[i][1][1])
 
        if u == v:
            continue
        ans += mst[i][0]
        union(u, v)
 
# Function to handle different queries
def query(type: int, u=0, v=0):
    global ans
 
    # Update edge weight to 0
    if type == 2:
 
        # push edge in zeros
        zeroes.append((u, v))
        modified_kruskal((-1, -1))
 
    # Restore edge weight to original value
    elif type == 3:
 
        # push edge in zeros
        zeroes.append((u, v))
        modified_kruskal((u, v))
    else:
        print(ans)
 
# Driver Code
if __name__ == "__main__":
 
    # Number of nodes and edges
    n = 4
    m = 4
    initialize()
 
    # Add edges
    add_edge(1, 2, 1)
    add_edge(2, 3, 1)
    add_edge(3, 4, 1)
    add_edge(4, 1, 1)
 
    # Build the minimum spanning tree
    compute_MST()
 
    # Execute queries
    query(2, 1, 2)
    query(1)
    query(3, 1, 2)
    query(1)
 
# This code is contributed by
# sanjeev2552


输出:
2
3

时间复杂度:每个查询 O(N),其中 N 是图中节点的总数。
辅助空间: O(N)