您的位置:首页 > 其它

菜鸟系列——二分图匹配

2015-07-25 17:04 204 查看

菜鸟就要老老实实重新学起:

二分图匹配——匈牙利算法(dfs实现)

dfs深搜找增广路经求二分图最大匹配。

//二分图匹配:二分图最大配对数
//最小点覆盖:选取最少的点覆盖所有边
//最大独立集:选取最多的点,集合中点之间无连接
//二分图最大匹配==最小点覆盖==总点数-最大独立集


模版:

#define N 1234
int n,m,cnt;
int f
;
int vm
,um
;
bool vis
;
vector<int>g
;
void init()
{
cnt = 0;
memset(f,-1,sizeof(f));
memset(vm,-1,sizeof(vm));
memset(um,-1,sizeof(um));
for(int i=0;i<=n+m;i++)
g[i].clear();
}
void inserts(int u, int v)
{
g[u].push_back(v);
g[v].push_back(u);
}
int dfs(int u)
{
int v;
for(int i=0;i<g[u].size();i++)
{
v = g[u][i];
if(vis[v])
continue;
vis[v] = 1;
//能直接找到增广路径或者连接该节点的节点有其他增广路径
if(vm[v] == -1 || dfs(vm[v])!=-1)
{
vm[v] = u; um[u] = v;
return v;
}

}
return -1;
}
//染色
void dye(int u)
{
int v;
for(int i=0;i<g[u].size();i++)
{
v = g[u][i];
if(f[v]!=-1)
continue;
f[v] = f[u]^1;
dye(v);
}
}
void Dye()
{
for(int i=1;i<=n;i++)
if(f[i] == -1)
{
f[i] = 0;
dye(i);
}
}
int maxMatch()
{
Dye();
int res = 0;
for(int i=1;i<=n;i++)
if(!f[i])
{
memset(vis,0,sizeof(vis));
if(dfs(i)!=-1)
res++;
}
//取得最大点集覆盖
return res;
}


二分图匹配——Hopcroft-Karp算法

就是先通过BFS找到增广路径集,用来更新匹配值,在点数较多时有不错的时间表现。

模版:

#define N 51234
vector<int>g
;
int um
,vm
,n;
int dx
,dy
,dis;
bool vis
;
void inserts(int u, int v)
{
g[u].push_back(v);
}
bool searchP()
{
queue<int>q;
dis=INF;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1;i<=n;i++)
if(um[i]==-1)
{
q.push(i);
dx[i]=0;
}
while(!q.empty())
{
int u=q.front();q.pop();
if(dx[u]>dis)  break;
for(int i=0;i<g[u].size();i++)
{
int v = g[u][i];
if(dy[v]==-1)
{
dy[v]=dx[u]+1;
if(vm[v]==-1)  dis=dy[v];
else
{
dx[vm[v]]=dy[v]+1;
q.push(vm[v]);
}
}
}
}
return dis!=INF;
}
bool dfs(int u)
{
for(int i=0;i<g[u].size();i++)
{
int v = g[u][i];
if(!vis[v]&&dy[v]==dx[u]+1)
{
vis[v]=1;
if(vm[v]!=-1&&dy[v]==dis) continue;
if(vm[v]==-1||dfs(vm[v]))
{
vm[v]=u;um[u]=v;
return 1;
}
}
}
return 0;
}
int maxMatch()
{
int res=0;
memset(um,-1,sizeof(um));
memset(vm,-1,sizeof(vm));
while(searchP())
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if(um[i]==-1&&dfs(i))  res++;
}
return res;
}


eg:

POJ1274 The Perfect Stall

http://poj.org/problem?id=1274

题意:

n个奶牛,m个谷仓,奶牛有自己喜欢的谷仓。

求最多有多少头牛能去自己喜欢的谷仓。

思路:

奶牛与谷仓即为二分图,匈牙利算法求最大匹配即可;

code:

#define N 1234

int n,m,cnt;
int f
;
int vm
,um
;
bool vis
;
vector<int>g
;
void init()
{
cnt = 0;
memset(f,-1,sizeof(f));
memset(vm,-1,sizeof(vm));
memset(um,-1,sizeof(um));
for(int i=0;i<=n+m;i++)
g[i].clear();
}
void inserts(int u, int v)
{
g[u].push_back(v);
g[v].push_back(u);
}
int dfs(int u)
{
int v;
for(int i=0;i<g[u].size();i++)
{
v = g[u][i];
if(vis[v])
continue;
vis[v] = 1;
if(vm[v] == -1 || dfs(vm[v])!=-1)
{
vm[v] = u; um[u] = v;
return v;
}

}
return -1;
}
int maxMatch()
{
int res = 0;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)!=-1)
res++;
}
return res;
}

int main()
{
int i,j,k,kk,t,x,y;
while(scanf("%d%d",&n,&m)!=EOF&&n)
{
init();
for(i=0;i<n;i++)
{
scanf("%d",&t);
for(j=0;j<t;j++)
{
scanf("%d",&y);
inserts(i+1,y+n);
}
}
printf("%d\n",maxMatch());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: