图论总结(10)二分图匹配

来源:互联网 发布:张伯礼 知乎 编辑:程序博客网 时间:2024/05/21 17:37

二分图匹配都能用网络流来解决,但代码太复杂。

先是简单的最大匹配(无权):

KM死磕了很久才看懂。

直接匈牙利:

模板:

//int S[maxn];int T[maxn];int Left[maxn];int m,n;//int Right[maxn];bool match(int i){for(int j=1;j<=n;j++)if(!T[j]&&G[i][j]){T[j]=true;if(!Left[j]||match(Left[j])){Left[j]=i;return true;}}return false ;}void KM(){memset(Left,0,sizeof(Left));int ans=0;for(int i=1;i<=m;i++){memset(T,0,sizeof(T));if(match(i))ans++;}cout<<ans;}

最大权匹配以及完美匹配

找了一个网上得模板,感觉比蓝书上的好

模板:

#include<iostream>#include<cstring>using namespace std;const int maxn=101;const int INF=0x3f3f3f3f;int lx[maxn],ly[maxn];bool S[maxn],T[maxn];int n,Left[maxn],w[maxn][maxn],Right[maxn];bool match(int i){S[i]=true;for(int j=1;j<=n;j++)if(!T[j]&&w[i][j]==lx[i]+ly[j]){T[j]=true;if(!Left[j]||match(Left[j])){Left[j]=i;Right[i]=j;return true;}}return false ;}void KM(){for(int i=1;i<=n;i++){Left[i]=lx[i]=ly[i]=Right[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(;;){memset(S,0,sizeof(S));memset(T,0,sizeof(T));if(match(i))break;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(lx[i]+ly[j]-w[i][j],a);for(int i=1;i<=n;i++){if(S[i])lx[i]-=a;if(T[i])ly[i]+=a;}}}int ans=0;for(int i=1;i<=n;i++)if(w[i][Right[i]]>0)ans+=w[i][Right[i]];cout<<ans;}int main(){freopen("in.txt","r",stdin);cin>>n;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){cin>>w[i][j];if(!w[i][j])w[i][j]=-INF;}KM();}


match函数和上面是一样的。

模板二(用slack优化):

#include<iostream>#include<cstring>using namespace std;const int maxn=101;const int INF=0x3f3f3f3f;int Left[maxn],T[maxn],S[maxn];int w[maxn][maxn];int lx[maxn],ly[maxn];int slack[maxn],n;int match(int i){S[i]=true;for(int j=1;j<=n;j++)if(!T[j]){if(lx[i]+ly[j]==w[i][j]){T[j]=true;if(!Left[j]||match(Left[j])){Left[j]=i;return true;}}else slack[j]=min(slack[j],lx[i]+ly[j]-w[i][j]);}return false ;}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(w[i][j],lx[i]);}for(int i=1;i<=n;i++){memset(slack,INF,sizeof(slack));for(;;){memset(S,0,sizeof(S));memset(T,0,sizeof(T));if(match(i))break;int a=INF;for(int i=1;i<=n;i++)if(!T[i])a=min(a,slack[i]);for(int i=1;i<=n;i++){if(S[i])lx[i]-=a;if(T[i])ly[i]+=a;}}}int ans=0;for(int i=1;i<=n;i++)if(w[Left[i]][i]>0)ans+=w[Left[i]][i];cout<<ans;}int main(){freopen("in.txt","r",stdin);cin>>n;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){cin>>w[i][j];if(!w[i][j])w[i][j]=-INF;}KM();}