您的位置:首页 > 其它

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

2014-08-10 00:03 387 查看
如果二分图的每条边都有的一个权值,如何求出权值和最大(最小)的匹配;

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

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 long

using 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 long

using 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐