基本概念:二分图有两种节点:X节点和Y节点。如果X和Y可以匹配, 则X与Y连着一条边。每个X节点最多只能匹配一个Y节点,同时每个Y节点最多只能匹配一个X节点。最大匹配便是最多的匹配数。
交错路径:交错路径中的边分为重边和轻边。每个每两个相邻的边的种类是不同的。对于两端的边都为轻边的一条交错路径,此时如果把轻边变成重边,重边变成轻边(以后此操作简称翻转),路径上重边的数量便会多一个。
在二分图最大匹配中,一个X一个X地,看看以下通过Dfs实现的操作能否成功:把当前X节点当作起点,图中已经匹配的边为潜在的重边,去寻找一个未匹配过的Y节点。如果操作成功,将找到的交错路径一翻转,匹配的数量就多了一个。最后输出总匹配的数量即可。
注意:Dfs的Vis标记在Y里,而不在X里。
#include <cstdio> #include <cstring> using namespace std; const int MAX_XNODE = 1010, MAX_YNODE = 1010, MAX_EDGE = MAX_XNODE*MAX_YNODE; #define LOOP(i, n) for(int i=1; i<=n; i++) struct Hungary { private: struct Xnode; struct Ynode; struct Edge; struct Xnode { Edge *Head; }_xNodes[MAX_XNODE]; int _xCnt; struct Ynode { Xnode *Match; bool Vis; }_yNodes[MAX_YNODE]; int _yCnt; struct Edge { Xnode *X; Ynode *Y; Edge *Next; }*_edges[MAX_EDGE]; int _eCnt; Edge *NewEdge() { return _edges[++_eCnt] = new Edge(); } bool Dfs(Xnode *x) { for (Edge *e = x->Head; e; e = e->Next) { if (!e->Y->Vis) { e->Y->Vis = true; if (!e->Y->Match || Dfs(e->Y->Match)) { e->Y->Match = x; return true; } } } return false; } public: Hungary(){} Hungary(int xCnt, int yCnt) :_xCnt(xCnt), _yCnt(yCnt), _eCnt(0) { memset(_xNodes, 0, sizeof(_xNodes)); memset(_yNodes, 0, sizeof(_yNodes)); memset(_edges, 0, sizeof(_edges)); } void AddEdge(int xId, int yId) { Xnode *x = _xNodes + xId; Ynode *y = _yNodes + yId; Edge *e = NewEdge(); e->X = x; e->Y = y; e->Next = x->Head; x->Head = e; } int GetMatchCnt() { int ans = 0; LOOP(xId, _xCnt) { LOOP(yId, _yCnt) _yNodes[yId].Vis = false; ans += Dfs(_xNodes + xId); } return ans; } }; int main() { #ifdef _DEBUG freopen("c:\noi\source\input.txt", "r", stdin); #endif int totX, totY, totE, xId, yId; scanf("%d%d%d", &totX, &totY, &totE); static Hungary g(totX, totY); while (totE--) { scanf("%d%d", &xId, &yId); if (xId > totX || yId > totY) continue; g.AddEdge(xId, yId); } printf("%d ", g.GetMatchCnt()); return 0; }