網路流

RVm1eL_o6II發表於2024-11-07

傳奇水題板塊,我有一萬道紫黑都是做網路流,常年做網路流的人都目光呆滯極度自卑智商逐年下降最後完全成為傻子後面忘了。

演算法難度-1分,思維難度比較高,至少在2024.6.12還沒法靠自己做出來題。

6.14:這個東西當作dp做可能會比較好想,連邊操作就是在跑大概的轉移方程,網路流就是自動從轉移方程裡找最優狀態。

11.7:水水,水水水。我要做一億道網路流。

最大流

圓桌問題

好像是最大流經典例題,每個單位的人不能坐一張桌子,所以任意一個單位連到桌子的容量為1,意思是隻能做一個這樣的人,超原給每個單位連 \(r_i\) 容量的邊,每個桌子給超匯連 \(c_i\) 的邊。跑最大流。

有解是要每個人都落座,看看最大流是不是總人數。

是了暴力掃就行。

蜥蜴

這種問題有一個套路,如果你只會最大流而想解決最小值問題,可以用蜥蜴總數減掉能逃離的蜥蜴最大總數。總-最大反答案=最小答案。

也就是說最大流跑出來的就是能跑掉的蜥蜴數。

所以從超原往每個有蜥蜴的柱子連1邊,一般從超原連出來的就是最基本的量。

能跳到邊緣的點就是出口,只要柱子還在就能一直跳蜥蜴,所以給這些點跟超匯連容量無窮的邊。

然後看怎麼跑跳柱子減高度的過程。使用拆點:把每個柱子拆成一個入點和一個出點,入點和出點連柱子高度的容量,這樣每個蜥蜴上了柱子就一定會佔用一個高度容量,也就相當於柱子變矮了。要跳柱子就要從一個柱子出點走到另一個柱子的入點,也是可以無限跳的,連無窮邊。

星際戰爭

這個是網路流+二分答案。

顯然連線武器和能打到的機器人,因為隨便打所以容量無窮,機器人連到超匯容量為血量。

然後看為什麼要二分答案。

在時間 \(t\) 時每個炮臺能一共打出 \(b_i*t\) 的傷害,這些傷害要分佈到機器人的血量上,如果現在拿這個數做容量從超原往炮臺連邊跑最大流,最後跑出來的最大流就是這段時間內炮臺能打出來的最大傷害總和。

看一下這個總和大於等於總血量就行了。然後二分答案時間。

二分時間是這類問題的一種常用套路。

士兵佔領

用蜥蜴那題的做題思路,看一下最大反答案即最多能空多少個格子。

這種格子問題有一種方法就是 \(x\)\(y\) 即座標間連邊,優勢在於:每個兵會同時對 \(l\)\(c\) 產生影響,如果用兵點向lc分別連邊(我最早的思路),那麼dinic是無法保證最大流會同時流向兩個點,模型就錯了。

如果是 \(x->y\) 連1邊那麼每個兵連向x連1邊後會繼續跑y,跑完就是一個座標點。

既然空點要最大,按照題意相當於每一行和列都最多空出來一個數,把容量取反跑最大流即可。

還有法2。

可以發現答案再大大不過 \(\sum C_i+\sum L_i\)。答案能不等於這個的原因在於:這種情況下我們認為每個兵只對 \(L,C\) 中的一個產生貢獻,但很明顯有一些兵可以同時對 \(L,C\) 產生貢獻,我們記這個兵數為 \(val\),那麼有 \(ans=\sum C_i+\sum L_i-val\)

我們發現其實這個 \(val\) 好求的不止一點,把每個超原容量為 \(L_i\)\(x\) 連1邊向 \(y\)\(y\)\(C_i\) 連超匯,那跑出來的最大流不就是兩個都貢獻的兵嗎...

緊急疏散

這個題挺噁心。

按照套路嘗試去二分答案撤離時間,由於一個門每個時間只能走一個人,可以考慮把每個門按時間拆成小點向超匯連1邊。

然後一群人因為有可能會堆在一個門上,所以距離一個點最短的門可能不是這個人的最優出口,我們預處理出每個門點 \(i\) 到某個人點 \(j\) 的距離 \(dis_{i,j}\),顯然這個人想走這個門撤離至少要在 \(tim\ge dis_{i,j}\) 往後。

考慮怎麼等,原本想的是直接把人點向這個門於 \(dis\) 後的所有時間門點連邊,這個想法太naive。題解做法:每個時間的門向下一個時間的這個門連無窮邊,這樣只用 \(anstime\) 條邊就可以處理所有想走這個門撤離的人的“等待”問題。

然後把每個人往他能到的門上連最短距邊,有了剛才的處理我們只需要連一條到時間門的邊就可以了。

在每次二分時間得到的圖上跑最大流,看看能不能全跑出去。

impossible的情況肯定是有人沒門出,最開始就能預處理出來。

細節太多了差評。

星際轉移問題

這個題空間得往大開否則你就會被各種奇怪溢位導致的詭異錯誤折磨致死(比如預處理完導致全域性都應該不動的超原編號變成15)。

按照套路用二分時間的圖跑人數最大流。

現在又會個套路即關於時間的處理:時間可以拿來影響容量(星際戰爭),也可以拿來按時間拆點影響圖的結構(緊急疏散和這道題)。

每個太空站可以塞無限多個人,我們按時間拆好點讓每個當前時間的太空站向下個時間的太空站連無窮邊,超原連時間0的地球站,時間ans的月球站連超匯。

這樣的好處就在於:飛船的運動就非常好處理了,飛船會在每個時間的每個站向下個時間的下個站轉移人,我們給他倆連容量邊,又因為飛船在任何一個時間的位置都可算,圖就可以建出來了。

放一個tj區特別清楚的圖。

酒店之王

弱智題。

這種雙要素的網路流有固定套路:超原連要素1,要素1連元素,元素連要素2。自己隨便拆點限流就行了。

但是不要超原->要素1->要素2這麼連,要不然你也不知道要素1對應的元素到底能不能到要素2。

奇怪的遊戲

不好想的一道題,本來人就菜,題一難直接腦袋空空檢視題解。

是這麼分析的:

因為每個格子會影響到相鄰的格子,所以可以給棋盤黑白染色(聽都沒聽過的處理方法啊喂!)

我們設若干次操作後全部格子變成同一個值 \(v\),設最早黑白格子的權值和為 \(val_1,val_0\),格子個數為 \(num_1,num_0\)。那麼應該有:

\[v*num_0-val_0=v*num_1-val_1 \]

\[ans=v*num_0-val_0 \]

翻譯成人話就是黑白格子權值增量相等。

\[v=\frac{val_0-val_1}{num_0-num_1} \]

我們可以直接透過網路流方法驗證是否成立,怎麼驗證之後說。

但是 \(num_0==num_1\) 時就不能這麼驗證了,得慢慢二分答案,答案上界很大,r甚至得到1e18。

這個建圖也挺牛逼的,二分答案最終格子的權值 \(v\),既然已經完成了黑白染色,那麼可以從黑格往相鄰白格連無窮邊,然後超原給黑格連 \(v-a_{loc}\) 邊,白格給超匯連 \(v-a_{loc}\) 邊,也就是容量即當前權值到目標權值的操作次數,連起來就可以處理黑白格同時加權的操作。我們算黑格的容量和 \(sum\),跑一個最大流 \(V\),如果 \(V==sum\) 說明不僅黑白格總權值增量相同,而且都達到了目標權值。

這這這思維太跳脫了,感覺還得練好多題才能想到...

舞會

思路想對了,二分答案,女的往超匯連 \(ans\) 邊,看看最大流是不是 \(n*ans\) 即可。

然後每個男女從自己都開一個不喜歡點,容量 \(k\)。喜歡了直接人點連 \(1\) 邊,不喜歡了就不喜歡點連 \(1\) 邊。

但是超原往男點連的也是 \(ans\) 邊而不是 \(inf\) 邊,這個我想錯了,我覺得要貪心給答案所以給的inf,想了一下因為可能出現一些inf海王男點給嗯往女點跑流結果把答案跑大了。

最小割

UPD:2024.6.22:唐氏課件把最小割放費用流後頭,網上自學完了才發現後面有。

有一個最小割最大流定理,因為最大流在增廣時會收到minf邊的限制,那麼這些minf邊合起來就是最小的割。感性理解一下就行。

進而最小割容量就是最大流。

為了“割”的有效即選擇關係更明確,經驗來看,最小割題目一般不給圖分層。

[國家集訓隊] happiness

最小割可以用於這種“選了A就不能選B”題目的處理。

如果不考慮同時選課給出的貢獻,那麼建圖就比較容易了(不應該直接取max嗎),S給人點連文科邊,人點再給T連理科邊,按照意義來看,我們給這圖跑一個最小割就是不選科目的最小損失即最優反答案,不按照意義看就直接跑最大流。

然後考慮怎麼處理同時選課。

手玩可以發現,如果你要用最小割做這個題,那麼被切除的邊提供的combo也應該被切除,或者說,在這個割內,再按照最大流的原理,combo分的容量邊很可能是與S(T)相連的。

事實就是這樣,我們從S像一個輔助點連文combo邊,再從輔助點往兩個相鄰的人點連無窮邊,對稱一個輔助點處理理科。這樣就會導致:如果我們要割掉這兩個人點的文理邊導致圖不連通,那麼他們的combo邊也必須被割掉(肯定不斷inf),要不然這兩條邊沒有斷掉的意義。

放一張tj圖。

線性代數

難搞。

\[D=(A\times B-C)\times A^T \]

\[= (\begin{bmatrix} \sum_ia_ib_{1,i} & \sum_ia_ib_{2,i} &\cdots \sum_ia_ib_{n,i} \end{bmatrix} -C)\times \begin{bmatrix} a_1 \\ a_2 \\ \vdots \\ a_n \end{bmatrix} \]

\[=\sum_{j=1}^na_j(\sum_{i=1}^na_ib_{j,i}-c_j) \]

\[=\sum_{j=1}^n\sum_{i=1}^na_ia_jb_{j,i}-\sum_{j=1}^na_jc_j \]

\(a_i\in\{0,1\}\),相當於成了貢獻前的條件。

對於每個 \(b_{j,i}\),僅當 \(a_i=a_j=1\) 時才能產生貢獻。

但同時的,一旦 \(a_i=1\) 將產生 \(c_i\) 的負貢獻。現在要讓正負貢獻之和最大。

我們把 \(b_{j,i}\) 求和,超原往 \(b_{j,i}\) 連貢獻邊,\(c_i\) 往超匯連邊,對應 \(b\) 往對應 \(c\) 連無窮邊。

這樣有一個什麼效果:跑最小割時要麼割斷 \(b_{j,i}\),要麼割 \(c\),我們拿剛才求的和對這個最小割作差,相當於要麼保留原有 \(b_{j,i}\) 的貢獻但是得給我扣掉 \(c\),要麼不扣 \(c\) 但是減掉你 \(b_{j,i}\) 的貢獻。

人員僱傭

原本用的happiness的方法,然後10pts。

先說我錯的思路,想的是人往超匯連 \(a_i\) 邊,超原往 \(ij\) 輔點連 \(3E_{i,j}(j>i)\) 邊,彙總 \(2*E\) 然後減去最小割。

如果只有一個人不選那麼是正確的,問題是:如果 \(i,j\) 兩個人都不選那麼這個模型會額外扣掉一個 \(E_{i,j}\)

然後看人說是最小割有一個原連小點,小點連匯,小點互聯的常用套路。

看一下兩個人選取貢獻吧:

  • 兩個都選,最後要減掉他們的 \(A_i\),貢獻為向其他選取經理的combo貢獻和,這倆人的combo貢獻也得加上。
  • 選一個,剪掉一個 \(A_i\),加上選的人和其他人的combo和,減掉另一個人和其他人(包括這個選的人)的combo和。
  • 都不選,不用減 \(A_i\),但是他倆向其他所有選取人的combo和得減,但他倆之間的combo不用減。

如果不考慮不選造成的負貢獻,那就超原往人點連其引導的和貢獻邊,人點往超匯連 \(A_i\) 邊,要麼掏 \(A_i\) 錢要麼丟正貢獻。

但是現在不掏 \(A_i\) 的錢還會導致他到其他所有點都產生 \(E_{i,j}\) 的負貢獻,而且一扣扣倆,\((i,j),(j,i)\) 各一次,所以從 \(i\) 向所有 \(j\)\(2E_{i,j}\) 邊。

用總收益減最小割。

千鈞一髮

弱智題不說了。

關於慣性思維:勾股數不一定互質,一個數的勾股數也不唯一配對。

圈地運動

不弱智題,純靠自己做出來的,開心。

其實得益於上文happiness的經驗積累。那道題在相同種類時有combo,這道題不同時有combo,那麼可以考慮那道題造輔助點的思路。

我們直接考慮對矩陣黑白染色,黑點的\(S->p->T\) 連結 \(A_i,B_i\) 邊,白點則連結 \(B_i,A_i\) 邊,同樣超原開輔助點連 \(C_{i,j}\),輔助點往對應點連無窮即可。

黑白染色相當於給每個點交叉了一下,不同就轉化為相同了。

最小割樹的東西今沒太心思學。開費用流去了。

費用流

(不知道為什麼大家不愛用更快的dinic費用流)

數字配對

建圖容易,但是改費用流板子也太呃呃了。以後這種東西板子原理還得再學學的。

晨跑

純板題,但是有一些非常詭異的問題。

code 1

	add(in(1),out(1),inf,0);
	add(in(n),out(n),inf,0);
	for(int i=1,u,v,c;i<=m;i++){
		scanf("%lld%lld%lld",&u,&v,&c);
		add(out(u),in(v),1,c);
	}
	for(int i=2;i<n;i++)add(in(i),out(i),1,0);
	dinic(S,T);

code 2

	for(int i=1,u,v,c;i<=m;i++){
		scanf("%lld%lld%lld",&u,&v,&c);
		add(out(u),in(v),1,c);
	}
	for(int i=2;i<n;i++)add(in(i),out(i),1,0);	
	add(in(1),out(1),inf,0);
	add(in(n),out(n),inf,0);

兩種不同順序的程式碼會輸出不同的答案且後者會在最後一個隨機大點與正確答案差1,我也不知道為什麼。

修車

首先為什麼他媽後連源匯還是會錯啊???

以後先連st相關邊然後不要相信自己現敲的板子。

其實不是特別好想,一開始想給車拆點,發現按時間拆點不現實。然後是這麼個思路,比如師傅 \(i\) 一共修了 \(k\) 輛車,那麼倒數第 \(j (j\in[1,k])\) 輛車會給拖延後面 \(j-1\) 輛車各一個 \(T_{i,j}\) 的時間,換句話說就是我們按師傅的修車數給師傅拆點,然後倒數第 \(l\) 輛車的師傅的費用是 \(T_{i,j}*l\)

這個題很像任務安排的 \(O(n^2)\) 式子的處理方法。

然後就好了,有個傻逼開著8000的n^2ll陣列往學校oj交了一萬發re。

美食節

可以發現是修車那道題的強化。

資料大了不止一點,而且經過一段時間的嘗試發現幾乎沒有新的性質。正解是動態開點最佳化建圖。

因為我們假設每個修車師傅或者廚子都要把車或者菜整完,總數是固定的。所以多開了很多點,如果我們讓圖更高效就行。

然後涉及到演算法原理,這塊我確實沒太看。第 \(j\) 個廚子加到 \(l\) 層後看一下 \((j,l)\) 這個點用了沒,用了就再開一個 \((j,l+1)\) 的點。

至於怎麼看:\((j,l)\) 與超原超匯的連邊被跑滿(或者增廣過)。

然後程式碼放一下因為我不會寫。

#include<bits/stdc++.h>
#define MAXN 110005
#define MAXM 2000005
#define N 105
#define int long long
//#define DEBUG wzw
#define loc(i,j) (i-1)*tot+j+n
using namespace std;
int n,m;
struct node{
	int v,w,c,nxt;
}edge[MAXM<<1];
int h[MAXN],tmp;
inline void add(int u,int v,int w,int c){
	edge[tmp]=(node){u,0,-c,h[v]};
	h[v]=tmp++;
	edge[tmp]=(node){v,w,c,h[u]};
	h[u]=tmp++;
	#ifdef DEBUG
	printf("%lld - w:%lld,c:%lld -> %lld\n",u,w,c,v);
	#endif
}
const int inf=1e18;
int flow,spend;
int top[MAXN],nxt[MAXN];
int p[N],tot,tim[N][N],S,T=MAXN-1;
queue<int >Q;
int dis[MAXN];
bool vis[MAXN];
inline int SPFA(int S,int T){
	while(!Q.empty())Q.pop();
	fill(dis,dis+MAXN,inf);
	dis[S]=0,vis[S]=1;
	Q.push(S);
	while(!Q.empty()){
		int u=Q.front();
		Q.pop();
		vis[u]=0;
		for(int i=h[u];i;i=edge[i].nxt){
			int v=edge[i].v,w=edge[i].w,c=edge[i].c;
			if(dis[v]>dis[u]+c&&w){
				dis[v]=dis[u]+c;
				if(!vis[v]){
					vis[v]=1;
					Q.push(v);
				}
			}
		}
	}
	return dis[T]!=inf;
}
inline int dfs(int u,int minf){
	if(u==T||!minf)return minf;
	int res=0;
	vis[u]=1;
	for(int i=h[u];i;i=edge[i].nxt){
		int v=edge[i].v,w=edge[i].w,c=edge[i].c;
		if(dis[v]==dis[u]+c&&w&&!vis[v]){
			int ans=dfs(v,min(minf,w));
			if(ans){
				res+=ans;
				minf-=ans;
				edge[i].w-=ans;
				edge[i^1].w+=ans;
				spend+=ans*c;
				nxt[u]=v;
				if(!minf)break;
			}
		}
	}
	if(!res)dis[u]=inf;
	vis[u]=0;
	return res;
}
inline void dinic(int S,int T){
	int res=0;
	while(SPFA(S,T)){
		res+=dfs(S,inf);
		for(int j=1;j<=m;j++){
			if(nxt[loc(j,top[j])]&&top[j]<tot){
				++top[j];
				int u=loc(j,top[j]);
				for(int i=1;i<=n;i++)add(i,u,1,tim[i][j]*top[j]);
				add(u,T,1,0);
			}
		}
	}
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld",&p[i]),tot+=p[i];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%lld",&tim[i][j]);
		}
	}
	for(int i=1;i<=n;i++){
		add(S,i,p[i],0);
		for(int j=1;j<=m;j++)add(i,loc(j,1),1,tim[i][j]);
	}
	for(int i=1;i<=m;i++){
		top[i]=1;
		add(loc(i,1),T,1,0);
	}
	dinic(S,T);
	printf("%lld",spend);
	return 0;
}

植物人大戰僵屍

溝槽的碼力題。

關於最大權閉合子圖問題:感覺就是最小割的標準題型啊(bushi,有常用處理方法是正權給一邊求和,負權拉到另一邊取正,和-最小割即為答案。

比較易懂感性理解。沒負權建不了圖咋辦?哥沒負權了你全拿走輸出和不就行了...

然後說這道題:

首先右邊的植物人能護住左邊的植物人,你想把左邊的植物人打死得先打死右邊的,右邊往左邊連邊。

然後一個植物人能攻擊到的植物人沒法打,起碼你得先把這個植物人拆掉,連邊。

然後你會發現植物人靠這兩種做法官官相護可以卡無敵,環和他的外向基環樹全無敵,先跑一遍拓撲給這些無敵點扔掉。

然後咱們現在連的邊都是無窮邊,因為題目是這麼規定的,你不能切斷他們的保護關係。

然後按照他們的權值正負來給超原超匯連邊。超原連正,超匯連負。

壽司餐廳

最大權閉合子圖問題,頹的,說一下連邊。

這個每一步都很騷了所以一塊一塊說。

如果只考慮收益的combo而不考慮費用,那麼在最大權閉合子圖問題中有常用策略(植物大戰殭屍那題也用了,這題沒反應過來):正貢獻輔助點與超原連,負貢獻輔助點和超匯連,全指取反,手玩一下你就會發現這樣解決了dinic無法解決負貢獻取捨的問題。後來想一下這tm不是最小割的思路嗎...越做越菜了還。

然後,輔助點是一段連續區間開的,也就是說輔助點要和每個區間內元素相連,邊數爆炸,所以會讓輔助點連結區間左右端點,然後這個輔助點再往比自己小的兩個區間連無窮邊,相當於"取了大區間那小區間也必須取"。

再考慮收費的問題,對於同一個編號的食物形成了一個二次函式,考慮斜率最佳化,我們把他拆開看,因為平方項和取了多少個沒關係,我們開一個輔助點往超匯連 \(m*cost^2\) 邊,所有這個編號的食物往這個輔助點連無窮邊,就實現了"只要點這個編號就必須掏且僅掏一次錢",然後一次項就再開一個輔助點(其實也可以直接用超匯)讓食物點往輔點連 \(cost\) 邊,輔助點往超匯連一條無窮邊即可。

題解區唯一的圖,但是貢獻的正反沒畫進去(畫進去太亂了)。

80人環遊世界

這就是個費用流題吧,每個點都要進出 \(v_i\) 次,拆個點,然後有 \(m\) 次無花費進入的機會拿一個輔點維護,剩下的按圖和費用連結就行。

然後想讓的做法是上下界最小費用流。還是拆點相當於出入點的連邊至少要經過 \(v_i\) 次,給個下界,然後跑就可以了。

支線劇情

每個劇情都要跑一次所以每個劇情邊有一個1的下界。累加建好邊之後給每個點往1點連無窮邊相當於重開。

在這個圖上跑費用流,加上一開始下界求得和即答案。

清理雪道

說是叫有源匯上下界最小流。

這種題有專門的處理方法,就是在超源超匯的基礎上開一個假的源匯。這個假的源匯和一般問題裡的超源匯差不多,但是是用來平衡流量的,先跑一邊最大流,然後連結這個假的源匯中的匯->源,再在殘量網路裡跑一次最大流,然後這條平衡邊的反邊就是需要的最小代價,挺神奇的。

星際競速

其實不好做,但是建圖和80人一樣,被秒了。

無限之環

溝槽的碼力題。又難又碼。也確實事牛逼題。

題面看完基本沒有思路,太怪了。最開始想的還是二分最大流。

拿到題解逆向工程分析思路:顯然獨立的介面只會出現在格子的交界處,也就是相鄰格子才會造成可行性影響,既然如此就可以黑白染色。把每個格子拆成上下左右四個點,根據管子型別連線到這個點,然後相鄰格子的相鄰上下左右點也相連。

這樣在旋轉之後給每個黑格埠開一個流,跑最大流到白格看看滿不滿就能知道可行性了。

然後處理旋轉的問題,我們肯定不能真的去旋轉的,看看能不能用網路流擬合旋轉的過程。

比如這樣的右上管道,如果我們順時針旋轉90°那麼他就會變成右下管道。

變幻的過程可以把原有的點連到新出現的點,然後!費用就是1。在這裡相當於把上點連一個 \(w=1,c=1\) 到下點。別的同理。太妙了。

然後旋轉180度費用是2,這種L型管道不用建那個2邊,因為兩個1邊都走正好會變成180的樣子。

這就能解釋I型管道為什麼不能旋轉了,這遊戲我玩過是能旋轉的,原因在於I管一旋轉就不太能拿網路流處理了。

所以!這個麼個圖跑最小費用最大流,驗一下流輸出費用即可。

海拔 && 狼抓兔子

可以看出這兩題都是最小割板子,但是巨大的點數和連邊會導致tle,所以說一下對偶圖解決最小割的解法。

文章傳送門
把題目給你的圖轉成對偶圖,然後在 \(S',T'\) 上跑一個最短路,這個最短路就是最小割,堆最佳化dij可以把dinic的玄學複雜度最佳化到 \(O(nlog^2n)\)

志願者招募

這裡說一下網路流中如何處理一蓋多問題。

這個很久以前就開始想了,輔助點就算,這道題提供了個新思路(感覺比較特化),按天數連邊處理,這個容量給成 \(inf-a_i\),費用為0,然後給人從 \(s->t+1\),費用為 \(c\),S連第1天,第n+1天連T,容量無窮。

這樣會形成一個什麼效果,第一次選擇最小花費增廣的時候會把我們非常鬼畜的天數邊儘量跑滿,然後所有天數邊的餘量會變為 \(a_{max}-a_i\)。由於我們跑的是最小費用最大流,那剩下的這點流量在T的時候是必須要跑滿的,此時就要用剛才連的帶費用邊補足。手玩一下就會發現你的dinic自己幫你跑了最優的選人方案。挺神奇的建圖。

新生舞會

做完發現發明了01分數規劃。

答案式子可以化。

\[C=\frac{a_1+a_2+\dots +a_n}{b_1+b_2+\dots +b_n} \]

\[\sum_{i=1}^n(a_i-Cb_i)\ge 0 \]

最大化C,顯然答案有單調性,考慮二分。

這裡面的 \(a_i,b_i\) 是要我們自己取的,硬試肯定不行,發現可以轉化為費用流模型:因為最後一定是要配 \(n\) 對的,超源往男點連 \(w=1,c=0\) 邊,女點往超匯連 \(w=1,c=0\) 邊,男女隨便連1邊,然後就可以用費用來處理上面的式子,在二分C的基礎上一個 \((i,j)\) 配對的費用就是 \(a_{i,j}-Cb_{i,j}\)。跑最大費用最大流驗C即可。

老C的方塊

老C不喜歡的塊裡隨便捏一個方塊他就喜歡了,這種一斷全斷的模型可以用初中物理電學的方法把不喜歡塊裡的點串起來跑最小割...

所以就出現了一個顯然的做法,拆出入點連代價邊,暴力掃所有特殊邊左(右)邊的那個方塊,掃到了就往周圍看能不能組成老C不喜歡的塊,然後把四個方塊連inf起來,跑一個最小割。

然後T飛了,透過一些手段我們發現加入了巨量的重複邊,這個重複邊的意思不是重邊,只是在別的邊的作用下它起不到約束作用。

再看看特殊邊和老C不喜歡塊的關係,我們發現,在一些染色下,不喜歡的塊總是經過座標系中的四個固定顏色。這裡引用tj區一張圖。

在塊點的串聯中一定存在連線方案使得經過顏色正好為黃黑紅綠。

所以我們按照這種方法給圖染色,然後令超源連線到黃點,綠點連線到超匯。然後還是掃所有點,按顏色查四聯通方塊的顏色,黃連黑黑連紅紅連綠即可。容易得到每個邊都有實際作用。

鏡面通道

水能過光就能過,我覺得扯淡,但好像挺對。驗相交跑最小割,水。

分組作業

這個挺難的,前幾天板刷直接被擊敗了。你為什麼不是黑。

combo太蛋疼,然後我懶得寫了,設一個傳送門,有事看tj。

相關文章