BZOJ5154 [Tjoi2014]匹配 【KM算法 + 枚举】

题目链接

BZOJ5154

题解

先跑出一个匹配方案
然后暴力删去每对匹配再检验一下答案是否减小

使用KM算法提升速度

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define pr pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 85,maxm = 100005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
	return out * flag;
}
int w[maxn][maxn],expa[maxn],expb[maxn],dl[maxn],cp[maxn],visa[maxn],visb[maxn];
int n,tcp[maxn],mv,ansi;
pr ans[maxn];
bool dfs(int u){
	visa[u] = true;
	REP(i,n) if (!visb[i]){
		int kl = expa[u] + expb[i] - w[u][i];
		if (!kl){
			visb[i] = true;
			if (!cp[i] || dfs(cp[i])){
				cp[i] = u; return true;
			}
		}
		else dl[i] = min(dl[i],kl);
	}
	return false;
}
inline int work(){
	REP(i,n) expa[i] = expb[i] = cp[i] = 0;
	REP(i,n) REP(j,n) expa[i] = max(expa[i],w[i][j]);
	REP(i,n){
		REP(j,n) dl[j] = INF;
		while (true){
			REP(j,n) visa[j] = visb[j] = false;
			if (dfs(i)) break;
			int kl = INF;
			REP(j,n) if (!visb[j]) kl = min(kl,dl[j]);
			REP(j,n){
				if (visa[j]) expa[j] -= kl;
				if (visb[j]) expb[j] += kl;
				else dl[j] -= kl;
			}
		}
	}
	int re = 0;
	REP(i,n) re += w[cp[i]][i];
	return re;
}
int main(){
	n = read();
	REP(i,n) REP(j,n) w[i][j] = read();
	mv = work(); printf("%d\n",mv);
	REP(i,n) tcp[i] = cp[i];
	REP(i,n){
		int tmp = w[tcp[i]][i];
		w[tcp[i]][i] = 0;
		if (work() < mv) ans[++ansi] = mp(tcp[i],i);
		w[tcp[i]][i] = tmp;
	}
	sort(ans + 1,ans + 1 + ansi);
	REP(i,ansi) printf("%d %d\n",ans[i].first,ans[i].second);
	return 0;
}

posted @ 2018-05-14 09:52  Mychael  阅读(243)  评论(0编辑  收藏  举报