二分图(匈牙利算法)
2018-03-21 19:05
162 查看
来自renfei的板子
补充定义和定理:
最大匹配数:最大匹配的匹配边的数目
最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
最大独立数:选取最多的点,使任意所选两点均不相连
最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。
定理1:最大匹配数 = 最小点覆盖数(这是 Konig 定理)
定理2:最大匹配数 = 最大独立数
定理3:最小路径覆盖数 = 顶点数 - 最大匹配数
hdu2444
poj3020
hdu1151
poj2594
hdu1054
补充定义和定理:
最大匹配数:最大匹配的匹配边的数目
最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
最大独立数:选取最多的点,使任意所选两点均不相连
最小路径覆盖数:对于一个 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; }
相关文章推荐
- 二分图的最大匹配 ————匈牙利算法 (转载了一个大神的趣味算法) poj3041(Asteroids)
- HDU 2444 (BFS+判断二分图+匈牙利算法)
- hdu2119(二分图+最小点覆盖+匈牙利算法)
- 二分图的最大匹配、完美匹配和匈牙利算法
- hdu5090 匈牙利算法二分图最大匹配问题
- 最大二分图最大匹配的匈牙利算法
- 二分图最大匹配-匈牙利算法
- HIHO #1122 : 二分图二•二分图最大匹配之匈牙利算法
- HDOJ 2063 过山车 ——二分图最大匹配(以邻接矩阵,邻接表为数据结构的匈牙利算法)
- 二分图的最大匹配 匈牙利算法
- 二分图最大匹配算法-匈牙利算法(Hungary)模板
- 匈牙利算法(二分图)
- 无权二分图(最大匹配,完美匹配)(匈牙利算法)andSDNUOJ1247
- 二分图 匈牙利算法
- 二分图—匈牙利算法(论版题)
- hihocoder 1122 : 二分图二•二分图最大匹配之匈牙利算法
- hiho1122_二分图匈牙利算法
- B - The Accomodation of Students (二分图染色判断+匈牙利算法)
- 二分图最大匹配-匈牙利算法
- HDU 1068 Girls and Boys (匈牙利算法 二分图的最大独立集数 )