[kuangbin带你飞]专题十 匹配问题 二分图最大权匹配
Posted 天翎月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[kuangbin带你飞]专题十 匹配问题 二分图最大权匹配相关的知识,希望对你有一定的参考价值。
二分图最大权匹配有km算法和网络流算法
km算法模板默认解决最大权匹配的问题 而使用最小费用最大流 是解决最小权匹配问题
这两种办法都可以求最大最小权 需要两次取反
TAT 感觉讲km会很难的样子...
km的模板题
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<string> #include<vector> #include<queue> #include<iostream> using namespace std; #define L long long bool visx[305] , visy[305] ; int sla[305] ; int linker[305]; int lx[305] , ly[305]; int n ; int c[305][305]; bool fin(int u ){ visx[u] = false ; for(int v = 1; v <= n ; v ++ ){ if(visy[v]){ int tmp = lx[u] + ly[v] - c[u][v] ; if(tmp == 0){ visy[v] = false ; if(linker[v] == -1 || fin(linker[v])){ linker[v] = u ; return true ; } } else { sla[v] = min (sla[v] , tmp ) ; } } } return false ; } int km(){ memset(linker, -1 ,sizeof(linker)); memset(ly , 0 ,sizeof(ly)) ; for(int i = 1; i <= n ; i ++ ){ lx[i] = 0 ; for(int j = 1; j <= n; j ++ ){ lx[i] = max(lx[i] , c[i][j]) ; } } for(int i = 1; i<= n ; i ++ ){ for(int j = 1 ; j <= n ; j ++ )sla[j] = 999999999; while(true){ memset(visx , true , sizeof(visx)) ; memset(visy , true , sizeof(visy)) ; if(fin(i))break ; int d = 999999999 ; for(int j = 1; j<= n ; j ++ ){ if(visy[j]){ d = min(d , sla[j]) ; } } for(int j = 1; j<= n ; j ++ ){ if(visx[j] == false){ lx[j] -= d; } if(visy[j] == false){ ly[j] += d ; } else { sla[j] -= d; } } } } int res = 0 ; for(int j = 1; j <= n ; j ++ ){ if(linker[j] != -1){ res += c[linker[j]][j]; } } return res ; } int main(){ while(scanf("%d",&n)!=EOF){ for(int i = 1; i <= n ;i ++) { for(int j = 1; j <= n ; j ++ ) scanf("%d",&c[i][j]) ; } int ans = km() ; printf("%d\n",ans ); } }
Q hdu3488
是一个要求将所有的点连为一些环 并且边权的加和最小
环的合并可以用最小费用最大流来做
可以转化为 每个点上都连着两条边 使总边和最小 即 求最小权匹配
建图 是左边n个点 右边n个点 那么 最后可以求出一个完备匹配 左边的x点和右边的x点上都有一条边相连
km算法和网络列解法都是可以的 km100+ms 费用流900+ms
km :
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<string> #include<vector> #include<queue> #include<iostream> using namespace std; #define L long long bool visx[305] , visy[305] ; int sla[305] ; int linker[305]; int lx[305] , ly[305]; int n , m ; int c[305][305]; bool fin(int u ){ visx[u] = false ; for(int v = 1; v <= n ; v ++ ){ if(visy[v]){ int tmp = lx[u] + ly[v] - c[u][v] ; if(tmp == 0){ visy[v] = false ; if(linker[v] == -1 || fin(linker[v])){ linker[v] = u ; return true ; } } else { sla[v] = min (sla[v] , tmp ) ; } } } return false ; } int km(){ memset(linker, -1 ,sizeof(linker)); memset(ly , 0 ,sizeof(ly)) ; for(int i = 1; i <= n ; i ++ ){ lx[i] = -999999999 ; for(int j = 1; j <= n; j ++ ){ lx[i] = max(lx[i] , c[i][j]) ; } } for(int i = 1; i<= n ; i ++ ){ for(int j = 1 ; j <= n ; j ++ )sla[j] = 999999999; while(true){ memset(visx , true , sizeof(visx)) ; memset(visy , true , sizeof(visy)) ; if(fin(i))break ; int d = 999999999 ; for(int j = 1; j<= n ; j ++ ){ if(visy[j]){ d = min(d , sla[j]) ; } } for(int j = 1; j<= n ; j ++ ){ if(visx[j] == false){ lx[j] -= d; } if(visy[j] == false){ ly[j] += d ; } else { sla[j] -= d; } } } } int res = 0 ; for(int j = 1; j <= n ; j ++ ){ if(linker[j] != -1){ res += c[linker[j]][j]; } } return res ; } int main(){ int t ; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m) ; for(int i = 1; i<= n ; i ++ ){ for(int j = 1; j <= n ; j ++) c[i][j] = - 999999999; } for(int i = 1 ; i <= m ; i ++ ){ int u , v, w; scanf("%d%d%d",&u,&v,&w); c[u][v] = max(c[u][v] , -w ); } int ans = km() ; printf("%d\n", -ans); } }
费用流 :
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<string> #include<vector> #include<queue> #include<iostream> using namespace std; #define L long long int n ; int m ; int cnt ; struct ed{ int v , nex ,cap , flow ,cost ; }e[405 * 405] ; int head[405]; int tol; int pre[405]; int dis[405]; bool vis[405]; void init(){ cnt = 0; memset(head, -1 ,sizeof(head)) ; } void add(int u , int v ,int cap ,int cost){ e[cnt].v = v; e[cnt].nex = head[u]; e[cnt].cap = cap ; e[cnt].cost = cost ; e[cnt].flow = 0 ; head[u] = cnt ; cnt ++ ; e[cnt].v = u ; e[cnt].nex = head[v] ; e[cnt].cap = 0 ; e[cnt].cost = -cost ; e[cnt].flow = 0 ; head[v] = cnt ; cnt ++ ; } bool spfa(int s, int t){ queue<int >que; for(int i = 0; i<= 2*n + 1; i ++ ){ dis[i] = 999999999 ; vis[i] = false ; pre[i] = -1 ; } dis[s] = 0; vis[s] = true ; que.push(s) ; while(!que.empty()){ int u = que.front() ; que.pop () ; vis[u] = false ; for(int i = head[u] ; i != -1 ; i = e[i].nex) { int v = e[i].v ; if(e[i].cap > e[i].flow && dis[v] > dis[u] + e[i].cost ){ dis[v] = dis[u] + e[i].cost ; pre[v] = i ; if(vis[v] == false ){ vis[v] = true ; que.push(v) ; } } } } if(pre[t] == -1)return false ; else return true ; } int fyl(int s , int t , int &cost){ int flow = 0; cost = 0; while(spfa(s,t)){ int minn = 999999999; for(int i = pre[t] ; i != -1 ; i = pre[e[i^1].v]){ if(minn > e[i].cap - e[i].flow){ minn = e[i].cap - e[i].flow ; } } for(int i = pre[t] ; i != -1 ; i = pre[e[i^1].v]){ e[i].flow += minn ; e[i^1].flow -= minn ; cost += e[i].cost * minn ; } flow += minn ; } return flow ; } int main(){ int t ; scanf("%d",&t); while(t--){ init(); scanf("%d%d",&n,&m); for(int i = 1; i <= m ; i ++ ){ int u , v , w; scanf("%d%d%d",&u,&v,&w); add(u,v+n,1,w); } for(int i = 1; i <= n ; i ++ ){ add(0,i,1,0); add(i+n, n*2 + 1 , 1 , 0) ; } int cost ; int flow = fyl(0,n*2+1,cost); printf("%d\n",cost); } }
以上是关于[kuangbin带你飞]专题十 匹配问题 二分图最大权匹配的主要内容,如果未能解决你的问题,请参考以下文章