二分图最大权最小权匹配

mac2024-03-24  32

#include<bits/stdc++.h> using namespace std; const int maxn=1e3,INF=1e9; int W[maxn][maxn],n,m; int Lx[maxn],Ly[maxn];//顶标 int Left[maxn];//右边第i个点对应的左边的点的编号 bool S[maxn],T[maxn];//是否在增广路 bool match(int i){ S[i]=true; for(int j=1;j<=n;j++)if(Lx[i]+Ly[j]==W[i][j] && !T[j]){//i到j可行 且 j未被访问 T[j]=true; if(!Left[j] || match(Left[j])){ //j未标记 或者 通过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]);//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]=Lx[i]=Ly[i]=0; for(int j=1;j<=n;j++)Lx[i]=max(Lx[i],W[i][j]); } for(int i=1;i<=n;i++){ for(;;){ for(int j=1;j<=n;j++) S[j]=T[j]=0; if(match(i)) break; else update(); } } } int main(){ scanf("%d%d",&n,&m); /* //针对最小权匹配 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) W[i][j]=-1e9; */ while(m--) { int u,v,w; scanf("%d%d%d",&u,&v,&w); /* //针对最大权匹配 W[u][v]=w; */ /* //针对最小权匹配 if(W[u][v]==-1e9) W[u][v]=-w; else W[u][v]=max(W[u][v],-w); */ } KM(); int sum=0; for(int i=1;i<=n;i++)sum+=W[Left[i]][i]; /* //针对最大权匹配 printf("%d\n",sum); */ /* //针对最小权匹配 printf("%d\n",-sum); */ return 0; }
最新回复(0)