您的位置:首页 > 其它

二分图(匈牙利算法)

2018-03-21 19:05 162 查看
来自renfei的板子

补充定义和定理:

最大匹配数:最大匹配的匹配边的数目

最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择

最大独立数:选取最多的点,使任意所选两点均不相连

最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。

定理1:最大匹配数 = 最小点覆盖数(这是 Konig 定理)

定理2:最大匹配数 = 最大独立数

定理3:最小路径覆盖数 = 顶点数 - 最大匹配数

下面给出匈牙利算法的 DFS 和 BFS 版本的代码

// 顶点、边的编号均从 0 开始
// 邻接表储存

struct Edge
{
int from;
int to;
int weight;

Edge(int f, int t, int w):from(f), to(t), weight(w) {}
};

vector<int> G[__maxNodes]; /* G[i] 存储顶点 i 出发的边的编号 */
vector<Edge> edges;
typedef vector<int>::iterator iterator_t;
int num_nodes;
int num_left;
int num_right;
int num_edges;


int matching[__maxNodes]; /* 存储求解结果 */
int check[__maxNodes];

bool dfs(int u)
{
for (iterator_t i = G[u].begin(); i != G[u].end(); ++i) { // 对 u 的每个邻接点
int v = edges[*i].to;
if (!check[v]) {     // 要求不在交替路中
check[v] = true; // 放入交替路
if (matching[v] == -1 || dfs(matching[v])) {
// 如果是未盖点,说明交替路为增广路,则交换路径,并返回成功
matching[v] = u;
matching[u] = v;
return true;
}
}
}
return false; // 不存在增广路,返回失败
}

int hungarian()
{
int ans = 0;
memset(matching, -1, sizeof(matching));
for (int u=0; u < num_left; ++u) {
if (matching[u] == -1) {
memset(check, 0, si
4000
zeof(check));
if (dfs(u))
++ans;
}
}
return ans;
}


queue<int> Q;
int prev[__maxNodes];
int Hungarian()
{
int ans = 0;
memset(matching, -1, sizeof(matching));
memset(check, -1, sizeof(check));
for (int i=0; i<num_left; ++i) {
if (matching[i] == -1) {
while (!Q.empty()) Q.pop();
Q.push(i);
prev[i] = -1; // 设 i 为路径起点
bool flag = false; // 尚未找到增广路
while (!Q.empty() && !flag) {
int u = Q.front();
for (iterator_t ix = G[u].begin(); ix != G[u].end() && !flag; ++ix) {
int v = edges[*ix].to;
if (check[v] != i) {
check[v] = i;
Q.push(matching[v]);
if (matching[v] >= 0) { // 此点为匹配点
prev[matching[v]] = u;
} else { // 找到未匹配点,交替路变为增广路
flag = true;
int d=u, e=v;
while (d != -1) {
int t = matching[d];
matching[d] = e;
matching[e] = d;
d = prev[d];
e = t;
}
}
}
}
Q.pop();
}
if (matching[i] != -1) ++ans;
}
}
return ans;
}


hdu2444

自己的匈牙利dfs板子+判断是否是二分图

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 201
using namespace std;
int Map[MAXN][MAXN];
int color[MAXN];//染色
int N, M;
bool judge(int u)//判断是否是二分图
{
for(int i = 1; i <= N; i++)
{
if(Map[u][i] == 0 && Map[i][u] == 0) continue;  ///注意判断条件,因为这是建的有向图了,因为在一般的二分图匹配的过程中是有向图和
///无向图都一样的,因为用的是match都做标记了,但是在这里dfs判断的时候就必须不一样了
if(color[u] == color[i]) return false;
if(!color[i])
{
color[i] = 3 - color[u];
if(!judge(i))
return false;
}
}
return true;
}
int match[MAXN];
bool used[MAXN];
int DFS(int u)
{
for(int i = 1; i <= N; i++)
{
if(Map[u][i] == 0) continue;
if(!used[i])
{
used[i] = true;
if(match[i] == -1 || DFS(match[i]))
{
match[i] = u;
return 1;
}
}
}
return 0;
}
void solve()
{
memset(Map, 0, sizeof(Map));
int a, b;
for(int i = 1; i <= M; i++)
{
scanf("%d%d", &a, &b);
Map[a][b] = 1;
}
memset(color, 0, sizeof(color));
color[1] = 1;
if(!judge(1))
{
printf("No\n");
return ;
}
int ans = 0;
memset(match, -1, sizeof(match));
for(int i = 1; i <= N; i++)
{
memset(used, false, sizeof(used));
ans += DFS(i);
}
printf("%d\n", ans);
}
int main()
{
while(scanf("%d%d", &N, &M) != EOF)
{
solve();
}
return 0;
}


二分图最大匹配+输出路径

hdu1289

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
int n, m, k;
int ans;
int mapp[110][110];
int line[555][555];
int used[555];
int gril[555];
int x[10010], y[10010];
int dfs(int x)
{
//printf("x=%d\n", x);
for (int i = 1; i <= n; i++)
{
if (line[x][i] && used[i] == 0)
{
//printf("%d %d\n", x, i);
used[i] = 1;
if (gril[i] == 0 || dfs(gril[i]))
{
gril[i] = x;
return 1;
}
}
}
return 0;
}
int main()
{
while (~scanf("%d", &n))
{
memset(mapp, 0, sizeof(mapp));
memset(line, 0, sizeof(line));
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
memset(gril, 0, sizeof(gril));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
scanf("%d", &mapp[i][j]);
if (mapp[i][j])
{
line[i][j] = 1;
//line[j][i]=1;
}
}
}
ans = 0;
for (int i = 1; i <= n; i++)
{
memset(used, 0, sizeof(used));
if (dfs(i))
ans++;
}
//printf("ans=%d\n", ans);
if (ans < n)
printf("-1\n");
else
{
int tot = 0;
int j;
for (int i = 1; i <= n; i++)
{
for (j = i; j <= n; j++)
{
if(gril[j]==i)
break;
}
if(j!=i)
{
x[tot]=i;
y[tot++]=j;
swap(gril[i],gril[j]);
}
}
printf("%d\n", tot);
for (int i = 0; i < tot; i++)
{
printf("C %d %d\n", x[i], y[i]);
}
}
}
return 0;
}


poj3020

最小路径覆盖

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=605;
char str[maxn][maxn];
int gril[maxn*maxn];
int used[maxn*maxn];
int m[maxn][maxn];
int n,nn;
int top;
int ans;
struct node
{
int v;
int nex;
} e[maxn*maxn];
int first[maxn*maxn];
void edge(int u,int v)
{
e[top].v=v;
e[top].nex=first[u];
first[u]=top++;
}
void init(int x,int y)
{
//printf("fsdjklf\n");

if(x-1>=0&&m[x-1][y])
{

edge(m[x][y],m[x-1][y]);
//edge(m[x-1][y],m[x][y]);
}
if(x+1<n&&m[x+1][y])
{

edge(m[x][y],m[x+1][y]);
//edge(m[x+1][y],m[x][y]);
}
if(y-1>=0&&m[x][y-1])
{

edge(m[x][y],m[x][y-1]);
//edge(m[x][y-1],m[x][y]);
}
if(y+1<nn&&m[x][y+1])
{
edge(m[x][y],m[x][y+1]);
//edge(m[x][y+1],m[x][y]);
}

}
int dfs(int x)
{
for(int i=first[x]; i!=-1; i=e[i].nex)
{

int p=e[i].v;
if(used[p]==0)
{
used[p]=1;
if(gril[p]==0||dfs(gril[p]))
{
gril[p]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int t;
int tt=1;
scanf("%d",&t);
while(t--)
{
memset(gril,0,sizeof(gril));
memset(str,0,sizeof(str));
memset(m,0,sizeof(m));
memset(first,-1,sizeof(first));
int tot=1;
top=0;
scanf("%d%d",&n,&nn);
for(int i=0; i<n; i++)
{

scanf("%s",str[i]);
for(int j=0; j<nn; j++)
{
if(str[i][j]=='*')
{
m[i][j]=tot++;
}
}
}
for(int i=0; i<n; i++)
{
for(int j=0; j<nn; j++)
{
if(m[i][j])
init(i,j);
}
}
//printf("fjsdlf\n");
ans=0;
for(int i=1; i<=tot; i++)
{
//printf("%d\n",i);
memset(used,0,sizeof(used));
if(dfs(i))
{
ans++;
}
}
printf("%d\n",tot-ans/2-1);
}
return 0;
}


hdu1151

#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1505;
int ans;
int tot;
int n,m;
struct node
{
int v;
int nex;
} e[maxn*4];
int first[4*maxn];
void edge(int u,int v)
{
e[tot].v=v;
e[tot].nex=first[u];
first[u]=tot++;
}
int used[maxn];
int g[maxn];
int dfs(int x)
{
for(int i=first[x]; i!=-1; i=e[i].nex)
{
int p=e[i].v;
if(used[p]==0)
{
used[p]=1;
if(g[p]==-1||dfs(g[p]))
{
//printf("%d\n",x);
g[p]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
ans=0;
tot=0;
memset(first,-1,sizeof(first));
memset(g,-1,sizeof(g));
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
edge(u,v);
//edge(v,u);
}
for(int i=1; i<=n; i++)
{
memset(used,0,sizeof(used));
if(dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
return 0;
}


poj2594

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
#define LL long long
const int maxn=505;
int g[maxn];
int used[maxn];
int line[maxn][maxn];
//int first[maxn];
int tot;
int n,m;
int ans;
//struct node
//{
//    int v;
//    int nex;
//} e[maxn];
//void edge(int u,int v)
//{
//    e[tot].v=v;
//    e[tot].nex=first[u];
//    first[u]=tot++;
//}
int dfs(int x)
{
for(int i=1;i<=n;i++)
{
if(line[x][i]&&used[i]==0)
{
used[i]=1;
if(g[i]==-1||dfs(g[i]))
{
g[i]=x;
return 1;
}
}
}
return 0;

}

void floy()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(line[i][k]&&line[k][j])
{
line[i][j]=1;
//edge(i,j);
}
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0)
return 0;
if(m==0)
{
printf("%d\n",n);
continue;
}
ans=0;
memset(line,0,sizeof(line));
memset(g,-1,sizeof(g));
//memset(first,-1,sizeof(first));
tot=0;
for(int i=0; i<m; i++)
{
int u,v;
scanf("%d%d",&u,&v);
line[u][v]=1;
//edge(u,v);
}
floy();
for(int i=1; i<=n; i++)
{
memset(used,0,sizeof(used));
if(dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
return 0;
}


hdu1054

最小点覆盖

#include<stdio.h>
#include<string.h>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1505;
int ans;
int tot;
struct node
{
int v;
int nex;
} e[maxn*4];
int first[4*maxn];
void edge(int u,int v)
{
e[tot].v=v;
e[tot].nex=first[u];
first[u]=tot++;
}
int used[maxn];
int g[maxn];
int dfs(int x)
{
for(int i=first[x]; i!=-1; i=e[i].nex)
{
int p=e[i].v;
if(used[p]==0)
{
used[p]=1;
if(g[p]==-1||dfs(g[p]))
{
//printf("%d\n",x);
g[p]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
ans=0;
tot=0;
memset(first,-1,sizeof(first));
memset(g,-1,sizeof(g));
for(int i=0; i<n; i++)
{
int u,p;
scanf("%d:(%d)",&u,&p);
//printf("%d %d\n",u,p);
for(int j=0; j<p; j++)
{
int v;
scanf("%d",&v);
edge(u,v);
edge(v,u);
}
}
for(int i=0; i<n; i++)
{
memset(used,0,sizeof(used));
if(dfs(i))
ans++;
}
printf("%d\n",ans/2);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: