二分图最大匹配与最小顶点覆盖(教程系列)uva11419——我目前关于最大匹配最清晰的解释。

来源:互联网 发布:mac风扇一直响 编辑:程序博客网 时间:2024/06/04 23:25

定义什么的百度拉拉,我只说证明.

1.假设我们现在已经用匈牙利算法求出了最大匹配,很明显现在已经木有增广路了(即未匹配->匹配->未匹配这些形式的路径,图里是木有的,不过一定要从下面说的那种特殊点开始)

2.现在我们从右边开始标记一些点沿着(未匹配->匹配->未匹配......->匹配)这种形式的路径进行,(特别注意的是这个起点一定没有和匹配边相邻接,为什么?看下面。)

标记路径上经过的所有点。注意起点是右边的点,结束时一定在匹配边结束。

标记完后已经木有从右边的这种点开始的未匹配边了!!!(然后我将证明所有左边已经标记的点和右边未标记的点的数目和,就是最小覆盖也等于最大匹配数)

3.对右边的点分类,标记了的点,和没标记的点,可以发现没标记的点都有和匹配边相连,显然。。。而且没标记的点对应的匹配边的左边那个点也是没标记的。显然。。

对于匹配边也阔以分为两类和右边的没标记的点相邻接,和右边的有标记的部分点相邻接=左边标记了的点数目,匹配边数这样分类时是木有重叠的,所以上述点数目和是最大匹配。

4.然后边又阔以分为两类。两个端点都是标记点,两个端点都是未标记点,嗯很显然等于上面描述的点数目,综上最大匹配数=最小覆盖。

5.最小覆盖<最大匹配是不可能的。。。

6.上述证明一定是正确的,我已经过了uva上的题了,用上面的证明。。。。。。。。。。(关键!!)不过要注意的对于那些度为0的点要排除掉!!!!!!!!!!!!!!!!!!!!!

此题就是把行当成左边点,列是右边点,然后n行m列有点的话让左边n号点连右边m点然后就是求一个最小覆盖。。

#include<iostream>#include<cstdio>#include<algorithm>#include<vector>using namespace std;vector<int>x[1050], y[1050];int visitx[1050], visity[1050], matchy[1050],matchx[1050];int getx[1050], gety[1050];int n, m,point;bool dfs(int num){visitx[num] = 1;for (int i = 0; i < x[num].size(); i++){int to = x[num][i];if (visity[to])continue;//说白了这一步你只能走未匹配边如果visity[to]=1代表走的是匹配边或者i正搜索中你继续走下去阔能有回路visity[to] = 1;         //还有就算你visity[to]=1你走后然后后增广你会发现那个y是和两个x相连的。。。if (matchy[to] == -1 ||  dfs(matchy[to]))//在dfs外面我们是一个一个遍历x的但是当开始dfs后要到x必须走匹配边而且是从y走所以这不用visitx[i]!=1这个条件{matchy[to] = num; matchx[num] = to;return true;}}return false;}int getans(int nn,int mm){int ans = 0;for (int i = 1; i <= nn; i++)matchx[i] = -1;for (int i = 1; i <= mm; i++)matchy[i] = -1;for (int i = 1; i <= nn; i++){for (int j = 1; j <= nn; j++)visitx[j] = 0;for (int j = 1; j <= mm; j++)visity[j] = 0;if (dfs(i))ans++;}return ans;}void mdfs(int num){gety[num] = 1; visity[num] = 1;for (int i = 0; i < y[num].size(); i++){int to = y[num][i];if (visitx[to])continue;//加速需要getx[to] = 1; visitx[to] = 1;mdfs(matchx[to]);}}void mark(int nn, int mm)//每个点最多遍历一次所以是o(n)的{for (int i = 1; i <= nn; i++)getx[i] = 0, visitx[i] = 0;for (int i = 1; i <= mm; i++)gety[i] = 0, visity[i] = 0;for (int i = 1; i <= mm; i++){if (visity[i]||y[i].size()==0)continue;if (matchy[i]==-1)mdfs(i);}}int main(){int k = 1;while (scanf("%d%d%d", &n, &m, &point)&&n&&m&&point){for (int i = 1; i <= n; i++)x[i].clear();for (int i = 1; i <= m; i++)y[i].clear();for (int i = 0; i < point; i++){int a, b;scanf("%d%d", &a, &b);x[a].push_back(b), y[b].push_back(a);}int ans = getans(n,m);mark(n,m);printf("%d", ans);for (int i = 1; i <= n; i++){if (getx[i] == 1)printf(" r%d", i);}for (int i = 1; i <= m; i++){if (gety[i] == 0&&y[i].size()!=0)printf(" c%d", i);}printf("\n");}return 0;}

阅读全文
0 0