二分图的最优匹配模版
2015-05-22 16:59
351 查看
二分图的的最优匹配是在求二分图的完备匹配的基础之上求出的, 通过不断的扩展完备匹配,最终达到相等子图。而相等子图的完备匹配就是最优匹配。在此定义了可行顶标。
一个关于最优匹配讲的很好的博客地址:http://www.cnblogs.com/one--world--one--dream/archive/2011/08/14/2138385.html
hdu2255
最大权最优匹配模版:
顶标lx【i】表示与顶点i相连的所有边的最大值; 顶标ly【j】为零(为了保证lx【i】+ly【j】>=w【i】【j】)
当不存在完备匹配时,进行扩展时,顶标lx减去扩展量, 顶标ly加上扩展量
时间复杂度为0(n^4)
poj2195(此题可以用费用流做)
最小权最优匹配模版:
求最小权最优匹配有两种方案:
(1)把所有的权值取反, 求最大权匹配,得到结果取反
(2)顶标lx【i】表示与顶点i相连的所有边的最小值; 顶标ly【j】为零(为了保证lx【i】+ly【j】<=w【i】【j】)
当不存在完备匹配时,进行扩展时,顶标lx加上扩展量, 顶标ly减去扩展量
一个关于最优匹配讲的很好的博客地址:http://www.cnblogs.com/one--world--one--dream/archive/2011/08/14/2138385.html
hdu2255
最大权最优匹配模版:
顶标lx【i】表示与顶点i相连的所有边的最大值; 顶标ly【j】为零(为了保证lx【i】+ly【j】>=w【i】【j】)
当不存在完备匹配时,进行扩展时,顶标lx减去扩展量, 顶标ly加上扩展量
时间复杂度为0(n^4)
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int maxn = 1000 + 10; int Map[maxn][maxn], n; int Ls[maxn], Lt[maxn], p[maxn]; bool vs[maxn], vt[maxn]; bool dfs(int u) { vs[u] = true; for(int v = 1; v <= n; v++) { if(Ls[u]+Lt[v]==Map[u][v] && !vt[v]) { vt[v] = true; if(p[v]==-1 || dfs(p[v])) { p[v] = u; return true; } } } return false; } void update() { int a = 1<<30; for(int i = 1; i <= n; i++) if(vs[i]) for(int j = 1; j <= n; j++) if(!vt[j]) a = min(a, Ls[i]+Lt[j]-Map[i][j]); for(int i = 1; i <= n; i++) { if(vs[i]) Ls[i] -= a; if(vt[i]) Lt[i] += a; } } void KM() { memset(p, -1, sizeof(p)); memset(Lt, 0, sizeof(Lt)); memset(Ls, 0, sizeof(Ls)); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) Ls[i] = max(Ls[i], Map[i][j]); for(int i = 1; i <= n; i++) { while(1) { memset(vs, false, sizeof(vs)); memset(vt, false, sizeof(vt)); if(dfs(i)) break; else update(); } } int ans = 0; for(int i = 1; i <= n; i++) ans += Map[p[i]][i]; printf("%d\n", ans); } int main() { while(~scanf("%d", &n)) { for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) scanf("%d", &Map[i][j]); KM(); } return 0; }时间复杂度为0(n^3)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 300 + 10; int sx[maxn], sy[maxn], vx[maxn], vy[maxn], match[maxn]; int money[maxn][maxn], slack[maxn]; int n; void chushihua() { memset(sy, 0, sizeof(sy)); for(int i = 1; i <= n; i++) { sx[i] = 1; for(int j = 1; j <= n; j++) { scanf("%d", &money[i][j]); sx[i] = max(sx[i], money[i][j]); } } } bool dfs(int x) { vx[x] = true; for(int i = 1; i <= n; i++) { int xx= sx[x] + sy[i] - money[x][i]; if(!vy[i] && !xx) { vy[i] = true; if(match[i]==-1 || dfs(match[i])) { match[i] = x; return true; } } else if(slack[i] > xx) slack[i] = xx; } return false; } void bestmatch() { for(int i = 1; i <= n; i++) { while(1) { memset(vx, false, sizeof(vx)); memset(vy, false, sizeof(vy)); memset(slack, 0x3f, sizeof(slack)); if(dfs(i)) break; int dd = inf; for(int i = 1; i <= n; i++) if(!vy[i] && dd>slack[i]) dd = slack[i]; for(int i = 1; i <= n; i++) { if(vx[i]) sx[i] -= dd; if(vy[i]) sy[i] += dd; } } } } int main() { while(~scanf("%d", &n)) { memset(match, -1, sizeof(match)); chushihua(); bestmatch(); int sum = 0; for(int i = 1; i <= n; i++) sum += money[match[i]][i]; printf("%d\n", sum); } return 0; }
poj2195(此题可以用费用流做)
最小权最优匹配模版:
求最小权最优匹配有两种方案:
(1)把所有的权值取反, 求最大权匹配,得到结果取反
(2)顶标lx【i】表示与顶点i相连的所有边的最小值; 顶标ly【j】为零(为了保证lx【i】+ly【j】<=w【i】【j】)
当不存在完备匹配时,进行扩展时,顶标lx加上扩展量, 顶标ly减去扩展量
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; const int maxn = 105; const int inf = 0x3f3f3f3f; struct Info { int x, y; }; char s[105]; int sm[maxn], sh[maxn]; int w[maxn][maxn], n; int p[maxn]; int lx[maxn], ly[maxn]; bool vx[maxn], vy[maxn]; int slack[maxn]; Info kk[maxn], tt[maxn]; void inin(int N, int M) { int cntm, cnth; cntm = cnth = 0; memset(w, 0, sizeof(w)); for(int i = 1; i <= N; i++) { scanf("%s", s); for(int j = 0; j < M; j++) { if(s[j] == 'm') { cntm++; kk[cntm].x = i; kk[cntm].y = j + 1; } else if(s[j] == 'H') { cnth++; tt[cnth].x = i; tt[cnth].y = j + 1; } } } n = cntm; for(int i = 1; i <= n; i++) { lx[i] = inf; ly[i] = 0; for(int j = 1; j <= n; j++) { int dd = abs(kk[i].x-tt[j].x) + abs(kk[i].y-tt[j].y); w[i][j] = dd; if(lx[i] > dd) lx[i] = dd; } } } bool dfs(int i) { vx[i] = true; for(int j = 1; j <= n; j++) { int xx = w[i][j] - lx[i] - ly[j]; if(!vy[j] && !xx) { vy[j] = true; if(p[j]==-1 || dfs(p[j])) { p[j] = i; return true; } } else if(slack[j] > xx) slack[j] = xx; } return 0; } void solve() { memset(p, -1, sizeof(p)); for(int i = 1; i <= n; i++) while(1) { memset(vx, false, sizeof(vx)); memset(vy, false, sizeof(vy)); memset(slack, 0x3f, sizeof(slack)); if(dfs(i)) break; int dd = inf; for(int i = 1; i <= n; i++) if(!vy[i] && dd>slack[i]) dd = slack[i]; for(int i = 1; i <= n; i++) { if(vx[i]) lx[i] += dd; if(vy[i]) ly[i] -= dd; } } int ans = 0; for(int i = 1; i <= n; i++) ans += w[p[i]][i]; printf("%d\n", ans); } int main() { int N, M; while(scanf("%d%d", &N, &M), N||M) { inin(N, M); solve(); } return 0; }
相关文章推荐
- poj 2195 二分图最优匹配 或 最小费用最大流
- hdu 1533 KM算法 二分图最优匹配
- HDU 2255 奔小康赚大钱(二分图最优匹配:模板题)
- HDU 3718 Similarity(二分图最优匹配)
- 51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)
- 二分图最大匹配数模版
- POJ 2195 Going Home(二分图最优匹配)
- HDUOJ 2195 二分图最优匹配
- hdu 3722 二分图 最优完备匹配 KM算法
- poj1904(二分图最优匹配)
- 二分图最优匹配 杭电 2255 KM算法
- hdu2255——奔小康赚大钱(二分图最优匹配+KM算法)
- POJ 2195 Going Home【二分图最优匹配.KM】
- hdu 3722 二分图 最优完备匹配 KM算法
- POJ 2195 Going Home(二分图最优匹配)
- HDU3722 Card Game 二分图之最优匹配 KM算法
- 匈牙利算法求二分图的最优匹配(java)
- KM算法,二分图的最优匹配,(也不知道怎么叫了)
- HDU 1853 Cyclic Tour(二分图最优匹配:有向环覆盖)
- hdu 2426 hdu 3718 二分图最优匹配算法KM