二分图的最大权匹配KM算法

 又搞了差不多一天,整天手残得没药可救了【摊手 

#include<cstdio>

#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<queue>
#define maxn 405
using namespace std;
const int inf=999999999;
typedef long long ll;
int matl[maxn],matr[maxn],visl[maxn],visr[maxn],lx[maxn],ly[maxn],slack[maxn];
int lnk[maxn],map[maxn][maxn],n,tag;
inline int max(int x,int y){if(x>y)return x;return y;}
inline int min(int x,int y){if(x<y)return x;return y;}
inline void modify(int x)
{
for(int y=matl[lnk[x]];x;x=y,y=matl[lnk[x]])//修改所有的增广路 
matl[matr[x]=lnk[x]]=x;//确定lnk并往回更新 
}
inline void augment(int now)
{
queue<int> Q;
Q.push(now);
visl[now]=++tag;//这里差点就忘写了 
for(;;)
{
while(!Q.empty())
{
now=Q.front();Q.pop();
for(int i=1;i<=n;i++)
if(visr[i]!=tag)
{
int d=lx[now]+ly[i]-map[now][i];
if(!d)
{
visr[i]=tag;
lnk[i]=now;
if(!matr[i]){modify(i);return;}//没有匹配,修改了到x的路就算找到了 
if(visl[matr[i]]!=tag)visl[matr[i]]=tag,Q.push(matr[i]);//已匹配,级数较高且不在当前层子图中 
}
else if(d<slack[i])slack[i]=d,lnk[i]=now;//slack:修改的最小差值 
}
}
int d=inf;
for(int i=1;i<=n;i++)if(visr[i]!=tag)d=min(d,slack[i]);//orz
for(int i=1;i<=n;i++)if(visl[i]==tag)lx[i]-=d;
for(int i=1;i<=n;i++)if(visr[i]==tag)ly[i]+=d;else if(slack[i]!=inf)slack[i]-=d;
for(int i=1;i<=n;i++)
if(visr[i]!=tag&&!slack[i])
{
visr[i]=tag;
if(!matr[i]){modify(i);return ;}
else if(visl[matr[i]]!=tag)visl[matr[i]]=tag,Q.push(matr[i]);
}
}
}
int main()
{
int nx,ny,m,temp1,temp2,temp3;
scanf("%d%d%d",&nx,&ny,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&temp1,&temp2,&temp3);
map[temp1][temp2]=temp3;
}
n=max(nx,ny);
for(int i=1;i<=n;i++)
{
lx[i]=-inf;
for(int j=1;j<=n;j++)
lx[i]=max(lx[i],map[i][j]);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
slack[j]=inf,lnk[j]=0;
augment(i);
}
ll ans=0;
for(int i=1;i<=nx;i++)
ans+=map[i][matl[i]];//这里手残打成matr了,苦于debug
printf("%lld\n",ans);
for(int i=1;i<=nx;i++)
printf("%d ",map[i][matl[i]]?matl[i]:0);
return 0;
}
posted @ 2017-04-19 22:07  OcahIBye  阅读(216)  评论(0编辑  收藏  举报