匈牙利算法:用来求二分图的最大匹配,核心在于求增广路径并且取反。也就是已经在匹配中的边变成不在匹配中的,不在配中的边变成在匹配中。
网上可以找到很多的代码,但是我还是自己写了一遍,实现的并不优美,全局变量多到爆炸,以后还是应该多看看别人的代码来学习。比如增广路径的寻找过程中找到一个已经在匹配中的边,这条边其实是不用找的,我的做法是在匹配矩阵中去遍历来寻找,但其实我们只要对右侧的点用数组记录这个点对应的匹配位置就可以了。
代码如下:
// 匈牙利算法.cpp : 定义控制台应用程序的入口点。 //今晚一定要把这个算法写完 不写完不睡觉 #include "stdafx.h" #include<iostream> #include<vector> using namespace std; vector<vector<bool>> connection, matched, inPath;//分别表示邻接矩阵,匹配结果,一条边是否在增广路径中 vector<bool> used; int m, n; bool dfs(int i, bool isInMatched) { if (!isInMatched)//分为是寻找在匹配中的边还是不在匹配中的边来寻找 此if下寻找不在匹配中的边 { for (int j = 1; j <= n; ++j) { if (connection[i][j] && !matched[i][j] && !inPath[i][j]) { inPath[i][j] = true; if (!used[j])//如果j点恰好为非饱和点,则满足要求,返回true { used[j] = true; return true; } else //否则以j为起点寻找一条在匹配中的边 { if (dfs(j, !isInMatched)) return true; else //如果找不到,则ij不可在路径中 { inPath[i][j] = false; } } } } return false;//若在循环中找到增广路径 则会返回true 否则在尾部返回false 表示在此点处找不到增广路径 } else//寻找在匹配中的边,本可以数组形式存储,省略此寻找过程,是我太傻 { for (int j = 1; j <= m; ++j) { if (matched[j][i] && !inPath[j][i]) { inPath[j][i] = true; if (dfs(j, !isInMatched)) return true; else { inPath[j][i] = false; } } } return false; } } int _tmain(int argc, _TCHAR* argv[]) { cin >> m >> n;//输入男生和女生的数目 vector<bool> temp(n + 1, false); vector<vector<bool>> Temp(m + 1, temp); used = vector<bool>(n + 1, false); inPath = connection = matched = Temp; int i, j; while (cin >> i >> j)//输入男生和与之匹配的女生的编号 { if (i > m || j > n) { cout << "Input Error"; break; } connection[i][j] = true; } cin.sync(); cin.clear(); for (i = 1; i <= m; ++i) { if (dfs(i, false))//dfs寻找增广路径 { for (int j = 1; j < m; ++j) { for (int k = 1; k < n; ++k) { if (inPath[j][k]) matched[j][k] = !matched[j][k]; } } inPath = Temp; } } for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (matched[i][j]) cout << i << "和" << j << "匹配" << endl; } } return 0; }