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; }