题目链接
题意
给定一个完全二分图,求最大权匹配
分析
模板题,提交时注意选c++,亲测G++超时。
790ms的代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=330;
int from[maxn],w[maxn][maxn];
int lx[maxn],ly[maxn],visx[maxn],visy[maxn],slack[maxn];
int nx,ny;
///定义slack[y]=min{lx[x]+ly[y]-w[x][y]},x已访问,y未访问
bool Find(int u)
{
visx[u]=1;
for(int v=0;v<ny;v++)if(!visy[v])
{
int tmp=lx[u]+ly[v]-w[u][v];
if(tmp==0)
{
visy[v]=1;
if(from[v]==-1 || Find(from[v]))
{
from[v]=u;
return true;
}
}
else slack[v]=min(slack[v],tmp);
}
return false;
}
int KM()
{
for(int i=0;i<nx;i++)
{
ly[i]=0;
lx[i]=-INF;
for(int j=0;j<ny;j++)
lx[i]=max(lx[i],w[i][j]);
}
memset(from,-1,sizeof(from));
for(int u=0;u<nx;u++)
{
for(int i=0;i<ny;i++) slack[i]=INF;
while(true)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(Find(u)) break;
int d=INF;
for(int i=0;i<ny;i++)if(!visy[i])
d=min(d,slack[i]);
for(int i=0;i<nx;i++)if(visx[i])
lx[i]-=d;
for(int i=0;i<ny;i++)
{
if(visy[i]) ly[i]+=d;
else slack[i]-=d;
}
}
}
int ans=0;
for(int i=0;i<ny;i++)
if(from[i]!=-1) ans+=w[from[i]][i];
return ans;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
nx=ny=n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&w[i][j]);
printf("%d\n",KM());
}
return 0;
}