二分图匹配都能用网络流来解决,但代码太复杂。
先是简单的最大匹配(无权):
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();
}