您的位置:首页 > 其它

uva11419 【最大二分匹配求最小点覆盖 匈牙利算法】

2017-07-25 08:45 274 查看
 uva11419 链接  


    题目大意:给一个由方格组成的二维平面,其中一些平面上有一些 目标需要清理,你可以从每次清理这个矩阵的一行或者一列,问清理位置。

   分析:把点转化为边,就变成求最小点覆盖,而最小点覆盖等于最大二分匹配。(挑程上有证明过程) 用匈牙利算法去求最大二分匹配。


求最小覆盖的步骤大致如下:


1)在右边找到一个未被匹配过的点,标记。


2)走一条没被匹配过的边,到左边的点,标记。


3)走一条匹配过的边到右边,标记。


4)重复2,3步骤直到不能再走。


5)回到步骤一,直到找不到未被匹配且未被标记的右边的点。


6)标记结束后,右边没有标记的点,和左边标记过的点,就可以覆盖所有的边。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector<int> g[1010];  //匈牙利算法建的是单向边,一维表x,二维表y。
int luk[1010],visx[1010],visy[1010],n,m,mark[1010],tot;
bool used[1010];
int dfs1(int u)//标记过程
{
visx[u]=1;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!visy[v])
{
visy[v]=1;
dfs1(luk[v]);
}
}
}
int dfs(int u)//匈牙利算法过程
{
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!used[v])
{used[v]=1;
if(luk[v]==-1||dfs(luk[v]))
{
luk[v]=u;
return 1;
}
}
}
return 0;
}
int erpi()
{
int res=0;
memset(luk,-1,sizeof(luk));
for(int i=1;i<=n;i++)
{
memset(used,0,sizeof(used));
if(dfs(i))res++;
}
return res;
}
int main()
{
int x,y;
while(scanf("%d%d%d",&n,&m,&tot)!=EOF&&(n||m||tot))
{
for(int i=1;i<=n;i++)g[i].clear();
while(tot--)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
}
int ans=erpi();
memset(mark,0,sizeof(mark));
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
for(int i=1;i<=m;i++)if(luk[i]!=-1)mark[luk[i]]=1;
for(int i=1;i<=n;i++) if(mark[i]==0)dfs1(i);
printf("%d",ans);
for(int i=1;i<=n;i++)if(!visx[i])printf(" r%d",i);
for(int i=1;i<=m;i++)if(visy[i])printf(" c%d",i);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐