KM算法:
题1:HDU 3488(Tour),二分图匹配求最小值,求最小值的时候可以先把每条边的权值取反求出最大值后,输出取反即可得出最小值。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int MAX=210;
#define Inf 100000000
#define min(a,b) (a)<(b)?(a):(b)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int Lx[MAX],Ly[MAX]; //顶标
int map[MAX][MAX];
int n,m,Link[MAX]; //Link为匹配边
int vx[MAX],vy[MAX],stack[MAX];
int Find(int pos)
{ vx[pos]=1;
for(int i=1;i<=n;i++)
if(!vy[i])
{ int val=Lx[pos]+Ly[i]-map[pos][i];
if(!val)
{ vy[i]=1;
if(Link[i]==-1||Find(Link[i]))
{ Link[i]=pos;
return 1;
}
}
else if(val<stack[i]) stack[i]=val;
}
return 0;
}
void KM()
{ for(int i=1;i<=n;i++)
{ Lx[i]=-Inf;
Ly[i]=0;
for(int j=1;j<=n;j++)
if(map[i][j]>Lx[i]) Lx[i]=map[i][j];
}
CLR(Link,-1);
for(int i=1;i<=n;i++)
{ fill(stack,stack+MAX,Inf);
while(1)
{ CLR(vx,0);
CLR(vy,0);
if(Find(i)) break;
int Min=Inf;
for(int j=1;j<=n;j++)
if(!vy[j]) Min=min(stack[j],Min);
for(int j=1;j<=n;j++)
if(vx[j]) Lx[j]-=Min;
for(int j=1;j<=n;j++)
if(vy[j]) Ly[j]+=Min;
}
}
}
int main()
{ int Case;
scanf("%d",&Case);
while(Case--)
{ for(int i=0;i<MAX;i++)
fill(map[i],map[i]+MAX,Inf);
scanf("%d%d",&n,&m);
int u,v,w;
for(int i=0;i<m;i++)
{ scanf("%d%d%d",&u,&v,&w);
if(w<map[u][v]) map[u][v]=w;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j]*=-1;
KM();
int sum=0;
for(int i=1;i<=n;i++)
if(Link[i]!=-1) sum+=map[Link[i]][i];
printf("%d\n",-sum);
}
return 0;
}