二分图最大权完美匹配(KM)

练习

【模板】二分图最大权完美匹配(洛谷)

代码

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,'\n');
	for(int i = 1;i <= n;++ i) Put(mat[i],' ');
	return 0;
}
posted @ 2021-02-05 21:25  皮皮刘  阅读(89)  评论(0编辑  收藏  举报