匈牙利算法
匈牙利算法的基本知识:
http://baike.baidu.com/view/501092.htm
维基百科: 这里面有邻接矩阵的模拟图
http://en.wikipedia.org/wiki/Hungarian_algorithm
http://www.cnblogs.com/jffifa/archive/2011/12/26/2302480.html
http://blog.csdn.net/leolin_/article/details/7199688
性质的证明:
http://wenku.baidu.com/view/d1b1b165783e0912a2162a9c.html
(v^3) 模版
#include <stdio.h> #include <string.h> int n1, n2, m, ans; int result[101]; //记录V2中的点匹配的点的编号 bool state [101]; //记录V2中的每个点是否被搜索过 bool data[101][101];//邻接矩阵 true代表有边相连 void init() { int t1, t2; memset(data, 0, sizeof(data)); memset(result, 0, sizeof(result)); ans = 0; scanf("%d%d%d", &n1, &n2, &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &t1, &t2);k data[t1][t2] = true; } return; } bool find(int a) { for (int i = 1; i <= n2; i++) { if (data[a][i] == 1 && !state[i]) //如果节点i与a相邻并且未被查找过 { state[i] = true; //标记i为已查找过 if (result[i] == 0 //如果i未在前一个匹配M中 || find(result[i])) //i在匹配M中,但是从与i相邻的节点出发可以有增广路 { result[i] = a; //记录查找成功记录 return true; //返回查找成功 } } } return false; } int main() { init(); for (int i = 1; i <= n1; i++) { memset(state, 0, sizeof(state)); //清空上次搜索时的标记 if (find(i)) ans++; //从节点i尝试扩展 } printf("%d\n", ans); return 0; }
(VE) 模版
View Code #include <iostream> #include <stdio.h> #include <memory.h> #include <vector> using namespace std; const int N = 1505; int pre[N]; bool flag[N]; vector<int> map[N]; int n; int find(int cur) { int i, k; for(i = 0; i < map[cur].size(); i++) { k = map[cur][i]; if(!flag[k]) { flag[k] = true; if(pre[k] == -1 || find(pre[k])) { pre[k] = cur; return 1; } } } return 0; } int main() { int i, j, r, k, num, sum; while(scanf("%d", &n) != EOF) { memset(pre, -1, sizeof(pre)); for(i = 0; i < n; i++) map[i].clear(); for(i = 0; i < n; i++) { scanf("%d:(%d)", &k, &num); for(j = 0; j < num; j++) { scanf("%d", &r); map[k].push_back(r); //用邻接表 map[r].push_back(k); //建双向图 } } sum = 0; for(i = 0; i < n; i++) { memset(flag, false, sizeof(flag)); sum += find(i); } printf("%d\n", sum/2); } return 0; }
题目:
模版题:
http://acm.hdu.edu.cn/showproblem.php?pid=2119
#include<stdio.h> #include<cstring> int map[105][105],n,m; int visit[105],result[105]; int dfs(int u) { for(int i=0;i<m;i++) { if(map[u][i]&&!visit[i]) { visit[i]=1; if(result[i]==-1||dfs(result[i])) { result[i]=u; return 1; } } } return 0; } int main() { while(scanf("%d",&n),n) { scanf("%d",&m); memset(result,-1,sizeof(result)); for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&map[i][j]); int sum=0; for(int i=0;i<n;i++) { memset(visit,0,sizeof(visit)); if(dfs(i)) sum++; } printf("%d\n",sum); } }
http://poj.org/problem?id=1274
http://poj.org/problem?id=2239
用x 轴的点集和y 轴的点集匹配 ,求最大匹配即为最小点覆盖
http://acm.hdu.edu.cn/showproblem.php?pid=1083
求完美匹配 水题
#include<stdio.h> #include<cstring> #define N 305 int map[N][N],n,m; int visit[N],result[N]; int dfs(int u) { for(int i=1;i<=m;i++) { if(map[u][i]&&!visit[i]) { visit[i]=1; if(result[i]==-1||dfs(result[i])) { result[i]=u; return 1; } } } return 0; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(map,0,sizeof(map)); memset(result,-1,sizeof(result)); for(int i=1;i<=n;i++) { scanf("%d",&map[i][0]); for(int j=1;j<=map[i][0];j++) { int x; scanf("%d",&x); map[i][x]=1; } } int sum=0; for(int i=1;i<=n;i++) { memset(visit,0,sizeof(visit)); sum+=dfs(i); } puts(sum==n? "YES":"NO"); } return 0; }
http://poj.org/problem?id=2536
#include<stdio.h> #include<cstring> #include<cmath> #define N 105 int map[N][N],n,m; int visit[N],result[N]; double pos[N][2]; int dfs(int u) { for(int i=1;i<=m;i++) { if(map[u][i]&&!visit[i]) { visit[i]=1; if(result[i]==-1||dfs(result[i])) { result[i]=u; return 1; } } } return 0; } int main() { int t,v; while( scanf("%d%d%d%d",&n,&m,&t,&v)!=EOF) { memset(map,0,sizeof(map)); memset(result,-1,sizeof(result)); memset(pos,0,sizeof(pos)); for(int i=1;i<=n;i++) { double x,y; scanf("%lf%lf",&pos[i][0],&pos[i][1]); } double road=t*v; for(int i=1;i<=m;i++) { double x,y; scanf("%lf%lf",&x,&y); for(int j=1;j<=n;j++) { double dis=(x-pos[j][0])*(x-pos[j][0])+(y-pos[j][1])*(y-pos[j][1]); dis=sqrt(dis); if(dis<=road) map[j][i]=1; } } int sum=0; for(int i=1;i<=n;i++) { memset(visit,0,sizeof(visit)); if(dfs(i)) sum++; } printf("%d\n",n-sum); } return 0; }
http://poj.org/problem?id=2771
条件有点多,男女匹配即可
#include<stdio.h> #include<cstring> #include<cmath> #define N 505 int map[N][N]; int nv,na; int visit[N],result[N]; struct node { int height; char sex; char mus[105],sport[105]; }male[N],famale[N]; int dfs(int u) { for(int i=1;i<=nv;i++) { if(map[u][i]&&!visit[i]) { visit[i]=1; if(result[i]==-1||dfs(result[i])) { result[i]=u; return 1; } } } return 0; } int main() { int t,n;scanf("%d",&t); while(t--) { scanf("%d",&n); memset(map,0,sizeof(map)); memset(result,-1,sizeof(result)); na=0,nv=0; for(int i=1;i<=n;i++) { int hei;char st; scanf("%d %c",&hei,&st); if(st=='M') { male[++na].height=hei; scanf("%s %s",male[na].mus,male[na].sport); } else { famale[++nv].height=hei; scanf("%s %s",famale[nv].mus,famale[nv].sport); } } for(int i=1;i<=na;i++) for(int j=1;j<=nv;j++) { int k=famale[j].height-male[i].height; if(fabs(k)<=40&&!strcmp(male[i].mus,famale[j].mus) &&strcmp(male[i].sport,famale[j].sport)) map[i][j]=1; } int sum=0; for(int i=1;i<=na;i++) { memset(visit,0,sizeof(visit)); sum+=dfs(i); } printf("%d\n",n-sum); } return 0; }
提高篇:
hdu 1054 Strategic Game
http://acm.hdu.edu.cn/showproblem.php?pid=1054
最小顶点覆盖 == 【最大匹配(双向建图)】/2
#include <iostream> #include <stdio.h> #include <memory.h> #include <vector> using namespace std; const int N = 1505; int pre[N]; bool flag[N]; vector<int> map[N]; int n; int find(int cur) { int i, k; for(i = 0; i < map[cur].size(); i++) { k = map[cur][i]; if(!flag[k]) { flag[k] = true; if(pre[k] == -1 || find(pre[k])) { pre[k] = cur; return 1; } } } return 0; } int main() { int i, j, r, k, num, sum; while(scanf("%d", &n) != EOF) { memset(pre, -1, sizeof(pre)); for(i = 0; i < n; i++) map[i].clear(); for(i = 0; i < n; i++) { scanf("%d:(%d)", &k, &num); for(j = 0; j < num; j++) { scanf("%d", &r); map[k].push_back(r); //用邻接表 map[r].push_back(k); //建双向图 } } sum = 0; for(i = 0; i < n; i++) { memset(flag, false, sizeof(flag)); sum += find(i); } printf("%d\n", sum/2); } return 0; }
最小顶点覆盖数=最大匹配数 还要注意 0 点不要算在内 注意多组数据清零
#include<stdio.h> #include<string.h> #define N 110 int map[N][N],vis[N],result[N]; int n,m,k; int find(int s) { for(int i=0;i<m;i++) { if(map[s][i]&&!vis[i]) { vis[i]=1; if(result[i]==-1||find(result[i])) { result[i]=s;return 1; } } } return 0; } int main() { while(scanf("%d",&n),n) { memset(result,-1,sizeof(result)); memset(map,0,sizeof(map)); scanf("%d%d",&m,&k); while(k--) { int w,u,v;scanf("%d%d%d",&w,&u,&v); map[u][v]=1; } int sum=0; for(int i=0;i<n;i++) { memset(vis,0,sizeof(vis)); sum+=find(i); } printf("%d\n",sum); } }
poj 1466 Girls and Boys
http://poj.org/problem?id=1466
最大独立集 == |P| 减 【最大匹配(双向建图)】/2 ;
#include <iostream> #include <stdio.h> #include <memory.h> #include <string.h> #include <vector> using namespace std; const int N = 1505; int pre[N]; bool flag[N]; vector<int> map[N]; int n; int find(int cur) { int i, k; for(i = 0; i < map[cur].size(); i++) { k = map[cur][i]; if(!flag[k]) { flag[k] = true; if(pre[k] == -1 || find(pre[k])) { pre[k] = cur; return 1; } } } return 0; } int main() { int i, j, r, k, num, sum; while(scanf("%d", &n) != EOF) { memset(pre, -1, sizeof(pre)); for(i = 0; i < n; i++) map[i].clear(); for(i = 0; i < n; i++) { scanf("%d: (%d)", &k, &num); for(j = 0; j < num; j++) { scanf("%d", &r); map[k].push_back(r); //用邻接表 map[r].push_back(k); //建双向图 } } sum = 0; for(i = 0; i < n; i++) { memset(flag, false, sizeof(flag)); sum += find(i); } printf("%d\n", n-sum/2); } return 0; }
hdu 1151 air raid
最小路径覆盖 == |P| 减 【最大匹配】,适用于有向无环图【DAG图
证明上面有连接
#include <iostream> #include <stdio.h> #include <memory.h> #include <vector> using namespace std; const int N = 1505; int pre[N]; bool flag[N]; vector<int> map[N]; int n,m; int find(int cur) { int i, k; for(i = 0; i < map[cur].size(); i++) { k = map[cur][i]; if(!flag[k]) { flag[k] = true; if(pre[k] == -1 || find(pre[k])) { pre[k] = cur; return 1; } } } return 0; } int main() { int i, r, k,sum;int cs;cin>>cs; while(cs--) { scanf("%d%d", &n,&m); memset(pre, -1, sizeof(pre)); for(i = 1; i <= n; i++) map[i].clear(); for(i = 1; i <= m; i++) { scanf("%d%d",&k, &r); map[k].push_back(r); //用邻接表 //map[r].push_back(k); //建双向图 } sum = 0; for(i = 1; i <= n; i++) { memset(flag, false, sizeof(flag)); sum += find(i); } printf("%d\n", n-sum); } return 0; }
http://blog.csdn.net/huanglianzheng/article/details/5605771
http://972169909-qq-com.iteye.com/blog/1154835
http://apps.hi.baidu.com/share/detail/15415702
http://www.ieee.org.cn/dispbbs.asp?boardID=60&ID=40964
http://hi.baidu.com/acmost/blog/item/a484e50fe2845ec37acbe14d.html