二分图的最大权匹配(最小权匹配)KM算法

来源:互联网 发布:广州软件培训学校 编辑:程序博客网 时间:2024/05/17 03:43

如果二分图的每条边都有的一个权值,如何求出权值和最大(最小)的匹配;

最小权值匹配可以转化最大权值匹配,只需将权值取相反数即可;

poj3565二分图最小权值匹配模板题目;

#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<climits>#include<cctype>#include<iostream>#include<algorithm>#include<queue>#include<vector>#include<map>#include<set>#include<stack>#include<string>#define INF 1e15#define eps 1e-6#define MAX 1000#define ll long longusing namespace std;double w[MAX][MAX],Lx[MAX],Ly[MAX];int Left[MAX],n;bool S[MAX],T[MAX];bool match(int i){S[i] = true;for (int j = 1; j<=n; j++) if (fabs(Lx[i] + Ly[j] - w[i][j]) <= eps && !T[j]){T[j] = true;if (!Left[j] || match(Left[j])){Left[j] = i;return true;}}return false;}void update(){double a = INF;for (int i = 1; i<=n; i++) if (S[i])for (int j = 1; j<=n; j++) if (!T[j]) a = min(a,Lx[i]+Ly[j] - w[i][j]);for (int i = 1; i<=n; i++){if (S[i]) Lx[i] -= a;if (T[i]) Ly[i] += a;}}void KM(){for (int i = 1; i<=n; i++){Left[i] = 0;Ly[i] = 0;Lx[i] = -INF;           //如果w[i][j]全是正整数的话可以将Lx[]赋0 for (int j = 1; j<=n; j++)Lx[i] = max(Lx[i],w[i][j]);}for (int i = 1; i<=n; i++){while (1){for (int j = 1; j<=n; j++) S[j] = T[j] = 0;if (match(i)) break;else update();}}}struct Node{int x, y;}p[MAX],q[MAX];double dist(int i, int j){return sqrt((double)(p[i].x - q[j].x)*(p[i].x - q[j].x) + (p[i].y - q[j].y) * (p[i].y - q[j].y));}int ans[MAX];int main(){while (scanf("%d",&n) != EOF){for (int i = 1; i<=n; i++) scanf("%d%d",&p[i].x,&p[i].y);for (int i = 1; i<=n; i++) scanf("%d%d",&q[i].x,&q[i].y);for (int i = 1; i<=n; i++)for (int j =1; j<=n; j++) w[i][j] = -dist(i,j);  //将权值取反,转化为最大权值匹配KM();for (int i = 1; i<=n; i++) ans[Left[i]] = i;for (int i = 1; i<=n; i++) printf("%d\n",ans[i]); }return 0;}
poj2195最小权值匹配;

#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<climits>#include<cctype>#include<iostream>#include<algorithm>#include<queue>#include<vector>#include<map>#include<set>#include<stack>#include<string>#define INF 1000000000#define eps 1e-6#define MAX 1000#define ll long longusing namespace std;int w[MAX][MAX],Lx[MAX],Ly[MAX];int Left[MAX],n;bool S[MAX],T[MAX];bool match(int i){S[i] = true;for (int j = 1; j<=n; j++) if (Lx[i] + Ly[j] == w[i][j] && !T[j]){T[j] = true;if (!Left[j] || match(Left[j])){Left[j] = i;return true;}}return false;}void update(){int a = INF;for (int i = 1; i<=n; i++) if (S[i])for (int j = 1; j<=n; j++) if (!T[j]) a = min(a,Lx[i]+Ly[j] - w[i][j]);for (int i = 1; i<=n; i++){if (S[i]) Lx[i] -= a;if (T[i]) Ly[i] += a;}}void KM(){for (int i = 1; i<=n; i++){Left[i] = 0;Ly[i] = 0;Lx[i] = -INF; for (int j = 1; j<=n; j++)Lx[i] = max(Lx[i],w[i][j]);}for (int i = 1; i<=n; i++){while (1){for (int j = 1; j<=n; j++) S[j] = T[j] = 0;if (match(i)) break;else update();}}}struct Node{int x, y;}p[MAX],q[MAX];int dist(int i, int j){return abs(p[i].x - q[j].x) + abs(p[i].y - q[j].y);}char s[MAX][MAX];int main(){int u,v;while (scanf("%d%d",&u,&v) && !(u == 0 && v == 0)){n = 0;int m = 0;for (int i=0; i<u; i++){scanf("%s",s[i]);for (int j = 0; j<v; j++){if (s[i][j] == 'm')p[++n] = (Node){i,j};if (s[i][j] == 'H')q[++m] = (Node){i,j};}}for (int i = 1; i<=n; i++)for (int j =1; j<=n; j++) w[i][j] = -dist(i,j);  //取相反数,转化为最大权问题 KM();int ans = 0;for (int i = 1; i<=n; i++) ans += dist(Left[i],i);printf("%d\n",ans);}return 0;}


0 0
原创粉丝点击