[jzoj5972]wang(最小权匹配=最小费用最大流、贪心、结论题)

5972. 【北大2019冬令营模拟12.1】 wang(2s,256MB)
Problem
  • 给定一个定义域和值域都在 Z Z Z上的函数 F ( x ) F(x) F(x),且给定一个常数 C C C,且满足 F ( 2 F ( x ) − x + 1 ) = F ( x ) + C F(2F(x) - x + 1) = F(x) + C F(2F(x)x+1)=F(x)+C

  • 现在给定你 n n n个二元组 ( x i , y i ) (x_i,y_i) (xi,yi),要求最小化 ∑ i = 1 n ∣ F ( x i ) − y i ∣ \sum_{i=1}^n|F(x_i)-y_i| i=1nF(xi)yi

Data constraint
  • C ≤ 60 C\le 60 C60

  • n ≤ 10000 n\le 10000 n10000

Solution
  • 性质①

    F ( x + 2 C ) = F ( x ) + 2 C F(x+2C)=F(x)+2C F(x+2C)=F(x)+2C

  • 证明①

  • y = 2 F ( x ) − x + 1 y=2F(x)-x+1 y=2F(x)x+1


  • F ( y ) = F ( x ) + C F(y)=F(x)+C F(y)=F(x)+C ⇓ \Downarrow F ( y ) + C = F ( x ) + 2 C F(y)+C=F(x)+2C F(y)+C=F(x)+2C ⇓ \Downarrow F ( 2 F ( y ) − y + 1 ) = F ( x ) + 2 C F(2F(y)-y+1)=F(x)+2C F(2F(y)y+1)=F(x)+2C 2 F ( y ) − y + 1 = 2 F ( y ) − 2 F ( x ) + x = x + 2 C 2F(y)-y+1=2F(y)-2F(x)+x=x+2C 2F(y)y+1=2F(y)2F(x)+x=x+2C ⇓ \Downarrow F ( x + 2 C ) = F ( x ) + 2 C F(x+2C)=F(x)+2C F(x+2C)=F(x)+2C

  • 性质②

    • a + b = 2 t + 1 , F ( a ) = t a+b=2t+1,F(a)=t a+b=2t+1,F(a)=t

    • F ( a ) + F ( b ) = 2 t + C F(a)+F(b)=2t+C F(a)+F(b)=2t+C

证明②

  • a = 2 a ′ , b = 2 b ′ + 1 , t = a ′ + b ′ a=2a',b=2b'+1,t=a'+b' a=2a,b=2b+1,t=a+b
  • F ( 2 F ( a ) − a + 1 ) = F ( a ) + C F(2F(a)-a+1)=F(a)+C F(2F(a)a+1)=F(a)+C ⇓ \Downarrow F ( 2 ( t + n C ) − a + 1 ) = t + n C + C F(2(t+nC)-a+1)=t+nC+C F(2(t+nC)a+1)=t+nC+C ⇓ \Downarrow F ( 2 t − a + 1 + 2 n C ) = t + n C + C F(2t-a+1+2nC)=t+nC+C F(2ta+1+2nC)=t+nC+C ⇓ \Downarrow F ( 2 t − a + 1 ) + 2 n C = t + n C + C F(2t-a+1)+2nC=t+nC+C F(2ta+1)+2nC=t+nC+C ⇓ \Downarrow F ( b ) = t − ( n − 1 ) C F(b)=t-(n-1)C F(b)=t(n1)C
  • 然后根据这两个性质,把所有的 X i X_i Xi按照 2 C 2C 2C取模之后可以分成 2 C 2C 2C组,每一组当中只要一个对应的值确立,整个组的值便可以确立.

  • 所以我们只需考虑组与组之间的对应关系

  • 并且根据题意,当 F ( a ) F(a) F(a)等于某个值 t t t时,只有 F ( 2 t − a + 1 ) F(2t-a+1) F(2ta+1) F ( a ) F(a) F(a)有关系,所以,很明显只有奇偶性不同的组互相影响.

  • 根据性质②,我们得知当 F ( a ) = t + n C F(a)=t+nC F(a)=t+nC时,对应的 F ( 2 t − a + 1 ) = t − ( n − 1 ) C F(2t-a+1)=t-(n-1)C F(2ta+1)=t(n1)C,换言之,对于所有的 X i X_i Xi,若其属于某组 a a a(即 X i ≡ a ( m o d   2 C ) X_i\equiv a(mod\ 2C) Xia(mod 2C)),那么可以考虑与其奇偶性不同的所有组 b b b,组 a a a与不同的组 b b b进行影响会产生不同的代价,而我们需要做的,是让所有的奇数组偶数组进行完美配对.

  • 要明白这一点,首先要知道什么叫完美配对.

  • 给定一个二分图,如果可以分成两个相等集合 S , T S,T S,T,并且 S S S中每个点与且仅与 T T T中一个点进行匹配,那么这个二分图就可以完美配对.

  • 对于此题而言,因为每个 F ( a ) F(a) F(a) 影响且仅能影响一个对应的 F ( b ) F(b) F(b),并且影响了 F ( b ) F(b) F(b)之后,既不能影响另一个 F ( c ) F(c) F(c),又不能被另一个 F ( c ) F(c) F(c)影响,所以这显然是一个二分图,显然是可以进行完美配对的。

  • 为了更好地计算出两组 a , b a,b a,b相互影响的代价,观察到实际上 F ( a ) F(a) F(a)只能变成 t + n C t+nC t+nC的形式,而 F ( b ) F(b) F(b)也是类似于这个形式,所以我们要计算 ∑ i = 1 n ∣ F ( X i ) − Y i ∣ \sum_{i=1}^n|F(X_i)-Y_i| i=1nF(Xi)Yi的代价,就可以想办法把式子转化成类似于 ∑ i = 1 n ∣ W i + n ∗ C ∣ \sum_{i=1}^n|W_i+n*C| i=1nWi+nC的形式,事实证明,这很容易做到.

  • 考虑两组 a , b a,b a,b,不妨假设 a = 2 a ′ , b = 2 b ′ + 1 a=2a',b=2b'+1 a=2a,b=2b+1,那么如果一个 X i X_i Xi在对应的 a a a组,我们就令 W i = F ( X i ) − Y i = F ( a ) + X i − a − Y i = a ′ + b ′ + X i − a − Y i W_i=F(X_i)-Y_i=F(a)+X_i-a-Y_i=a'+b'+X_i-a-Y_i Wi=F(Xi)Yi=F(a)+XiaYi=a+b+XiaYi

  • W i = a ′ + b ′ + X i − a − Y i W_i=a'+b'+X_i-a-Y_i Wi=a+b+XiaYi.

  • 反之,如果 X i X_i Xi b b b组,我们就令 W i = F ( X i ) − Y i = F ( b ) + X i − b − Y i = a ′ + b ′ + C + X i − b − Y i W_i=F(X_i)-Y_i=F(b)+X_i-b-Y_i=a'+b'+C+X_i-b-Y_i Wi=F(Xi)Yi=F(b)+XibYi=a+b+C+XibYi,因为 W i W_i Wi在式子里是套上了绝对值的,所以我们可以把它变成 W i = Y i + b − a ′ − b ′ − X i − C W_i=Y_i+b-a'-b'-X_i-C Wi=Yi+babXiC

  • W i = Y i + b − a ′ − b ′ − X i − C W_i=Y_i+b-a'-b'-X_i-C Wi=Yi+babXiC

  • 这样一来,所有的 ∣ F ( X i ) − Y i ∣ |F(X_i)-Y_i| F(Xi)Yi都可以变化成 ∑ i = 1 n ∣ W i + n ∗ C ∣ \sum_{i=1}^n|W_i+n*C| i=1nWi+nC.

  • 我们取中位数,并适当调整,可以很容易确定一个最优的 n n n.

  • 这样子便可以计算出两组 a , b a,b a,b进行配对的最优代价,接下来就是如何最小权匹配了.

  • 对于这个算法,我们可以直接转化最小费用最大流.

  • 最小费用最大流需要注意它是在保证最大流的前提下最小费用的,所以我们可以按照正常思维,从原点向左边一排点连容量为 1 1 1,费用为 0 0 0的边,汇点同样向右边一排点这样连边,之后,对于中间的连边,流量为 1 1 1,费用就是匹配代价,之后用 Z K W ZKW ZKW算法跑一遍就可以得到答案了.

  • 因为本人太菜,所以这里大致讲一讲费用流的实现.

  • 求解费用流一般有两种算法:第一种就是刚刚提到的大名鼎鼎的 Z K W ZKW ZKW算法,也是实战中经常用到的算法,另外一种就是经典的 s p f a spfa spfa增广算法.

SPFA增广
  • 一句话,每次找一条费用最小的流进行增广,直到不能增广为止.
#define I register int

void link(I x, I y, I z, I l) {
	tov[++ tot] = y, len[tot] = z, nex[tot] = las[x], cost[tot] =  l, las[x] = tot;
	tov[++ tot] = x, len[tot] = 0, nex[tot] = las[y], cost[tot] = -l, las[y] = tot;
}

bool spfa() {
	queue<int> q;
	mem(d, 0xcf), mem(v, 0), q.push(S), d[S] = 0, v[S] = 1, incf[S] = 1 << 30;
	while (q.size()) {
		I x = q.front(); v[x] = 0; q.pop();
		for (I i = las[x], y = tov[i]; i; i = nex[i], y = tov[i])
			if (len[i] && d[y] < d[x] + cost[i]) {
				d[y] = d[x] + cost[i], incf[y] = min(incf[x], len[i]), pre[y] = i;
				if (!v[y]) v[y] = 1, q.push(y);
			}
	}
	return d[T] > 0;
}

void update() {
	for (I x = T; x ^ S;)
		len[pre[x]] -= incf[T], len[pre[x] ^ 1] += incf[T], x = tov[pre[x] ^ 1];
	maxflow += incf[T], ans += d[T] * incf[T];
}

while (spfa()) update();
ZKW算法
#define ll long long

void link(ll x, ll y, ll l, ll L) {
	tv[++ tt] = y, c[tt] = L, nx[tt] = ls[x], ls[x] = tt, len[tt] =  l;
	tv[++ tt] = x, c[tt] = 0, nx[tt] = ls[y], ls[y] = tt, len[tt] = -l;
} //c[x]表示x这条边的流量,len[x]表示x这条边的费用


bool bfs() { //这里与spfa增广几乎是一模一样的,核心都是找出从原点到所有点的最小费用.
	mem(vis, 0), mem(dis, 0x7f), dis[S] = 0, vis[S] = 1;
	queue <ll> Q; Q.push(S);
	
	while (!Q.empty()) {
		ll k = Q.front(); Q.pop();
		for (ll x = ls[k]; x ; x = nx[x])
			if (c[x] && dis[tv[x]] > dis[k] + len[x]) {
				dis[tv[x]] = dis[k] + len[x]; //更新最小费用
				if (!vis[tv[x]])
					vis[tv[x]] = 1, Q.push(tv[x]);
			}
		vis[k] = 0;
	}

	return dis[T] < 9187201950435737471;
}

ll dfs(ll k, ll flow) {
	if (k == T) { vis[T] = 1; return flow; }
	ll have = 0; vis[k] = 1;
	//这里一定要注意这个vis标记的作用,因为dis[i]表示的是最小费用,而并非普通dinic的距离标号
	//所以这是可能存在零环的,因此一定要用个标记来去掉零环带来的影响.
	for (ll x = ls[k]; x ; x = nx[x])
		if (!vis[tv[x]] && c[x] && dis[tv[x]] == dis[k] + len[x]) {
			ll now = dfs(tv[x], min(flow - have, c[x]));
			ans += now * len[x], c[x] -= now, c[x ^ 1] += now, have += now;
			if (flow == have) return have;
		}
	return have;
}

int main() {
	while (bfs())
		for (vis[T] = 1; vis[T]; )
			mem(vis, 0), dfs(S, inf);
}

  • 实际上 Z K W ZKW ZKW的算法就是借鉴了普通的最大流 d i n i c dinic dinic算法以及原始 s p f a spfa spfa算法。

  • 在求出了 d i s [ i ] dis[i] dis[i],即最小花费之后每次多路增广,而不仅仅只是增广一条最优的路径(这是 s p f a spfa spfa增广),这样可以少进行很多次 s p f a spfa spfa,提高效率.

  • 所以综上,也不难发现,在稠密图上 Z K W ZKW ZKW一般是占据优势的,但在极稀疏的图上, s p f a spfa spfa增广一般更优.

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值