带权二分图最佳匹配(KM)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int head[1010],to[100010],w[1010][1010],nxt[100010],link[100010],dis[100010],tot=0;
bool vis[1010];
int INF=0x7f7f7f7f;
void add(int u,int v)
{
to[++tot]=v,nxt[tot]=head[u],head[u]=tot;
return;
}
bool find(int x)
{
int v;
for(int i=head[x];i;i=nxt[i])
if(!vis[v=to[i]]&&dis[i]+dis[v]==w[i][v])
{
vis[v]=1;
if(!link[v]||find(link[v])){
link[v]=x,link[x]=v;return 1;}
}
return 0;
}
int KM()
{
int ans=0,sum,i,j;
memset(dis,0,sizeof(dis));
for(i=1;i<=n;++i)
for(dis[i]=-INF,j=n+1;j<=n+n;++j)
dis[i]=dis[i]<w[i][j]?w[i][j]:dis[i];
memset(link,0,sizeof(link));
for(i=1;i<=n;++i)
while(1)
{
memset(vis,0,sizeof(vis));
if(find(i))break;
for(sum=INF,j=1;j<=n;++j)
{
if(vis[j])
for(k=n+1;k<=n+n;++k)
if(!vis[k])sum=min(sum,dis[j]+dis[k]-w[j][k]);
if(sum==INF)return -1;
for(j=1;j<=n;++j)
if(vis[j])dis[j]-=sum;
for(j=n+1;j<=n+n;++j)
if(vis[j])dis[j]+=sum;
}
}
for(i=1;i<=n;++i)
if(link[i])ans+=w[link[i]][i];
return ans;
}
int main()
{
int n,m,e,u,v,wt,i,ans;
memset(head,0,sizeof(head));
memset(vis,0,sizeof(vis));
memset(link,0,sizeof(link));
scanf("%d%d%d",&n,&m,&e);
for(int i=0;i<e;++i)
scanf("%d%d%d",&u,&v,&w[u][v]),v+=n,add(u,v),add(v,u);
printf("%d",KM());
return 0;
}