小菜本菜 2021-05-20 10:49 采纳率: 0%
浏览 25

求一个一般图最大匹配(带花树算法)的c语言版本

C++基础太薄弱了,希望大佬能写个c语言版本的,估计才有看懂的可能性。😭

  • 写回答

1条回答 默认 最新

  • Gary_HanJR 2023-04-11 09:30
    关注

    一般图最大匹配问题是指在一个无向图中找到一个由边组成的集合,其中任意两条边均无公共顶点,并且该集合的大小尽可能大。带花树算法是一种求解一般图最大匹配问题的经典算法之一,下面是带花树算法的C语言实现:

    
    ```c
    #include <stdio.h>
    #include <string.h>
    #define MAXN 1000
    
    int n, m;
    int match[MAXN], fa[MAXN];
    int mark[MAXN], stk[MAXN], top;
    bool g[MAXN][MAXN];
    
    int find(int u) {
        int d = u;
        while (d != fa[d]) {
            d = fa[d];
        }
        int p, tmp;
        while (u != d) {
            p = fa[u];
            fa[u] = d;
            tmp = match[u];
            match[u] = match[p];
            match[p] = tmp;
            u = p;
        }
        return d;
    }
    
    void blossom(int u, int v, int t) {
        while (1) {
            u = find(u);
            mark[u] = t;
            if (!match[u]) {
                break;
            }
            v = match[u];
            mark[v] = t;
            u = stk[top--] = fa[v];
        }
        if (u) {
            for (int i = 1; i <= n; i++) {
                if (mark[i] == t && g[u][i]) {
                    fa[i] = u;
                    stk[++top] = i;
                }
            }
        }
    }
    
    bool dfs(int u) {
        for (int i = 1; i <= n; i++) {
            if (g[u][i] && fa[u] != fa[i]) {
                if (match[i]) {
                    fa[i] = u;
                    if (dfs(match[i])) {
                        return true;
                    }
                } else {
                    int d = u, p = i, v;
                    while (d != fa[d]) {
                        stk[++top] = d;
                        v = match[d];
                        mark[d] = 1;
                        mark[v] = 1;
                        g[d][v] = g[v][d] = 1;
                        d = fa[d];
                    }
                    stk[++top] = d;
                    mark[d] = 1;
                    g[d][p] = g[p][d] = 1;
                    match[p] = d;
                    while (top) {
                        blossom(stk[top], p, 0);
                        blossom(stk[top--], p, 0);
                    }
                    return true;
                }
            }
        }
        return false;
    }
    
    int max_match() {
        memset(match, 0, sizeof(match));
        for (int i = 1; i <= n; i++) {
            fa[i] = i;
        }
        for (int i = 1; i <= n; i++) {
            if (!match[i]) {
                top = 0;
                if (dfs(i)) {
                    match[i] = -1;
                }
            }
        }
        int res = 0;
        for (int i = 1; i <= n; i++) {
            res += (match[i] > 0);
        }
        return res;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            g[u][v] = g[v][u] = 1;
        }
        int ans = max_match();
        printf("%d\n", ans);
        return 0;
    }
    

    其中,match[i]表示顶点i匹配的点的编号,如果match[i] = 0,则表示该点未被匹配,match[i] > 0表示该点被匹配到了编号为match[i]的点,match[i] < 0表示该点被标记为“花朵”(下文会讲到),-match[i]表示与该花朵匹配的点。

    fa[i]表示顶点i在并查集中的父亲节点,stk数组是辅助数组,用于保存花朵的一些信息,mark数组表示当前图中与某个点相连的边是否在花朵中,g[i][j]为真表示顶点i和顶点j之间有边相连。
    find()函数实现的是路径压缩的并查集。
    blossom()函数实现了从顶点u到顶点v的路径上所有非匹配边构成的花朵的收缩操作。
    dfs()函数实现了从顶点u开始的增广路查找,并在找到增广路时将对应的匹配边进行调整,如果找不到增广路则返回false。
    max_match()函数实现了求解最大匹配的主体程序,其中遍历每个未匹配的点,尽可能将该点匹配到一个未被匹配的点上,如果找到增广路则将对应的匹配关系进行调整。
    最终输出的答案就是最大匹配的大小。
    希望对您有所帮助!

    以下是C++版本,可以对应看一下:
    
    ```c++
    #include <bits/stdc++.h>
    using namespace std;
    
    const int MAXN = 1000;
    
    int n, m;
    int match[MAXN], fa[MAXN];
    int mark[MAXN], stk[MAXN], top;
    bool g[MAXN][MAXN];
    
    int find(int u) {
        int d = u;
        while (d != fa[d]) {
            d = fa[d];
        }
        int p, tmp;
        while (u != d) {
            p = fa[u];
            fa[u] = d;
            tmp = match[u];
            match[u] = match[p];
            match[p] = tmp;
            u = p;
        }
        return d;
    }
    
    void blossom(int u, int v, int t) {
        while (1) {
            u = find(u);
            mark[u] = t;
            if (!match[u]) break;
            v = match[u];
            mark[v] = t;
            u = stk[++top] = fa[v];
        }
        if (u) {
            for (int i = 1; i <= n; i++) {
                if (mark[i] == t && g[u][i]) {
                    fa[i] = u;
                    stk[++top] = i;
                }
            }
        }
    }
    
    bool dfs(int u) {
        for (int i = 1; i <= n; i++) {
            if (g[u][i] && fa[u] != fa[i]) {
                if (match[i]) {
                    fa[i] = u;
                    if (dfs(match[i])) return true;
                } else {
                    int d = u, p = i, v;
                    while (d != fa[d]) {
                        stk[++top] = d;
                        v = match[d];
                        mark[d] = 1;
                        mark[v] = 1;
                        g[d][v] = g[v][d] = 1;
                        d = fa[d];
                    }
                    stk[++top] = d;
                    mark[d] = 1;
                    g[d][p] = g[p][d] = 1;
                    match[p] = d;
                    while (top) {
                        blossom(stk[top], p, 0);
                        blossom(stk[top--], p, 0);
                    }
                    return true;
                }
            }
        }
        return false;
    }
    
    int max_match() {
        memset(match, 0, sizeof(match));
        for (int i = 1; i <= n; i++) {
            fa[i] = i;
        }
        for (int i = 1; i <= n; i++) {
            if (!match[i]) {
                top = 0;
                if (dfs(i)) {
                    match[i] = -1;
                }
            }
        }
        int res = 0;
        for (int i = 1; i <= n; i++) {
            res += (match[i] > 0);
        }
        return res;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            g[u][v] = g[v][u] = 1;
        }
        int ans = max_match();
        printf("%d\n", ans);
        return 0;
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥20 关于游戏c++语言代码问题
  • ¥15 如何制作永久二维码,最好是微信也可以扫开的。(相关搜索:管理系统)
  • ¥15 delphi indy cookie 有效期
  • ¥15 labelme打不开怎么办
  • ¥35 按照图片上的两个任务要求,用keil5写出运行代码,并在proteus上仿真成功,🙏
  • ¥15 免费的电脑视频剪辑类软件如何盈利
  • ¥30 MPI读入tif文件并将文件路径分配给各进程时遇到问题
  • ¥15 pycharm中导入模块出错
  • ¥20 Ros2 moveit2 Windows环境配置,有偿,价格可商议。
  • ¥15 有关“完美的代价”问题的代码漏洞