定义什么的百度拉拉,我只说证明.
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;
}