练习
【模板】二分图最大权完美匹配(洛谷)
代码
const LL INF = 0x3f3f3f3f3f3f3f3f;
int head[MAXN],tot;
struct edge
{
int v,w,nxt;
}e[MAXM];
void Add_Edge(int x,int y,int z)
{
e[++tot] = edge{y,z,head[x]};
head[x] = tot;
}
LL d[MAXN],lx[MAXN],ly[MAXN];
bool vis[MAXN];
int mat[MAXN];
void update(int x){for(int i = head[x]; i ;i = e[i].nxt) d[e[i].v] = Min(d[e[i].v],lx[x] + ly[e[i].v] - e[i].w);}
bool dfs(int x)
{
for(int i = head[x]; i ;i = e[i].nxt)
{
if(lx[x] + ly[e[i].v] == e[i].w && vis[e[i].v])
{
vis[e[i].v] = 0;
if(!mat[e[i].v] || dfs(mat[e[i].v]))
{
mat[e[i].v] = x;
return 1;
}
}
}
return 0;
}
void KM()
{
for(int u = 1,s;u <= n;++ u)
{
for(int i = 1;i <= n;++ i) vis[i] = 0,d[i] = INF;
update(u);
while(1)
{
LL MIN = INF;
for(int i = 1;i <= n;++ i)
if(!vis[i] && MIN > d[i])
MIN = d[i],s = i;
if(!MIN)
{
vis[s] = 1;
if(!mat[s]) {dfs(u);break;}
else update(mat[s]);
}
else
{
for(int i = 1;i <= n;++ i)
if(vis[i]) ly[i] += MIN,lx[mat[i]] -= MIN;
else d[i] -= MIN;
lx[u] -= MIN;
}
}
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); m = Read();
for(int i = 1,u,v;i <= m;++ i)
{
u = Read(),v = Read();
Add_Edge(u,v,Read());
}
for(int i = 1;i <= n;++ i)
{
lx[i] = -INF;
for(int j = head[i]; j ;j = e[j].nxt)
lx[i] = Max(lx[i],0ll+e[j].w);
}
KM();
for(int i = 1;i <= n;++ i) ans += lx[i] + ly[i];
Put(ans,'
');
for(int i = 1;i <= n;++ i) Put(mat[i],' ');
return 0;
}