簡單最大流 最小割複習

2022-04-05 20:34:04 字數 4349 閱讀 1936

主要用來複習一下自己之前學過的網路流。

因為當時都是直接抄的題解,莫得印象。所以寫篇部落格加強記憶。

先分析題目。

比較明顯,如果我們用網路流的思路去分析這個問題。將會將每個單位和每個餐桌都看做點。然後由於每個單位的人理論上可以坐在任意餐桌,同時對於乙個餐桌乙個單位只能有乙個人。所以每個單位向每個餐桌連一條容量為\(1\)的邊。

第\(i\)個單位最多有\(r_i\)人,所以從原點向它連容量為\(r_i\)的邊。

餐桌同樣考慮。

如果最大流等於總人數.說明有可行方案。

#include#include#include#include#include#include#includeusing namespace std;

const int n = 1e5 + 3;

const int m = 2e5 + 3;

const int inf = 2e9;

struct edgee[n << 1];

vector g[n];

int head[n],high[n];

int ci[n],ri[n],cur[n];

int n,m,s,t;

int tot = 1,sum;

inline int read()

while(isdigit(ch))

return v * c;

}inline void add(int x,int y,int flow)

inline bool bfs()

} return high[t] != 0;

}inline int dfs(int x,int dis)

} }return 0;

}inline int dinic()

return res;

}int main()

for(int i = 1;i <= m;++i)

for(int i = 1;i <= n;++i)

for(int j = 1;j <= m;++j)

add(i,j + n,1),add(j + n,i,0);

if(dinic() != sum) printf("0\n");

else

for(int i = 1;i <= n;++i)

} return 0;

}

依舊是最大流的典型例題。

我們設總的覆蓋路徑條數為\(s\),覆蓋了\(c\)條邊,共有\(n\)個點

那麼有:

所以我們要最小化\(s\),只需要最大化\(c\)即可。

我們發現,由於每個點必須且只能被覆蓋一次。所以這個點的所有入邊和出邊只能貢獻乙個。我們將點\(v\)拆成兩個點\(v\)與\(v'\)分別表示\(v\)點的入度與出度

如果原圖中存在一條邊\((u,v)\)

那麼就連一條從\(u'\)到\(v\)的流量為\(1\)的邊。

借用一下_\(rqy\)的圖

大概就是這個樣子。

本質上貌似是乙個二分圖的最大匹配問題

#include#include#include#include#include#include#includeusing namespace std;

const int n = 1e3 + 3;

const int m = 1e5 + 3;

const int inf = 2e9;

struct edgee[m << 1];

int head[n],high[n];

int pre[n],nt[n],cur[n],sta[n];

int n,m,tot = 1,s,t,top;

vector g[n];

inline int read()

while(isdigit(ch))

return v * c ;

}inline void add(int x,int y,int flow)

inline bool bfs()

} return high[t] != 0;

}inline int dfs(int x,int dis)

} }return 0;

}inline int dinic()

return res;

}inline void work(int x)

} flag = find; }}

int main()

for(int i = 1;i <= n;++i) add(s,i,1),add(i,s,0);

for(int i = n + 1;i <= n << 1;++i) add(i,t,1),add(t,i,0);

int sum = n - dinic();

for(int i = head[t];i;i = e[i].nxt)

for(int i = 1;i <= top;++i)

work(i);

for(int i = 1;i <= top;++i)

printf("%d\n",sum);

return 0;

}

首先,模型解釋

把圖上的點劃分成兩個集合,使得 \(s\) 和\(t\) 不在同乙個集合中,並最小化從 \(s\) 所在集合到 \(t\) 所在集合的所有邊的邊權之和

或者說刪掉代價最小的邊使得圖不連通

共有\(n\)個物品,每個物品都有其價值(可以為負),有部分限制比如說(選\(i\)必須選\(j\),即\(i\)依賴於\(j\)),求選擇物品的最大價值。

我們考慮將最小割中的兩個集合\(s\),\(t\)分別看作選與不選。

將所有的正權物品向匯點連一條流量為其權值的邊,表示不選擇物品會損失其權值。

將源點向所有的負權物品連一條流量為其權值相反數的邊,表示選擇這個物品會獲得其權值也就是損失其相反數的收益。

如果物品\(i\)依賴於\(j\),那麼就從\(j - i\)連一條權值為\(+\infty\)表示\(i,j\)在同一集合

最後將所有正權之和減去最小割即可

根據上面的最大權閉合子圖的模型,我們便很容易建出圖來

將實驗看做正權物品,裝置看做負權物品

再次借用_\(rqy\)的圖

我的理解:

滿流的邊是被割掉的邊。左邊\(l_3,l_4\)滿流表示購買這兩個裝置

右邊\(e_2,e_1\)滿流表示不做這兩個實驗

#include#include#include#include#include#include#includeusing namespace std;

const int n = 1e2 + 2;

const int inf = 2e9;

struct edgee[n * n];

int n,m;

int head[n],cur[n],high[n];

int s,t,tot = 1;

bool flag;

int sum = 0;

vector a1[n * n],ans1;

set ans2;

inline void build(int x,int y,int z)

inline void add(int x,int y,int z)

inline bool bfs()

} return high[t];

}inline int dfs(int x,int dis)

} }return 0;

}inline int dinic()// for(int i = 1;i <= n + m;++i) cout << high[i] << endl;

return res;

}int main()

}ulen++;

} }for(int i = 1;i <= n;++i)

int now = dinic();

// for(int i = 1;i <= n + m;++i) cout << high[i] << endl;

for(int i = 1;i <= m;++i)

if(high[i + n] == 0) printf("%d ",i);

printf("\n");

for(int i = 1;i <= n;++i)

if(high[i] == 0)printf("%d ",i);

printf("\n%d\n",sum - now);

return 0;

}

最大流 最小割

真是不知道該說些什麼呀 感覺這是我見到過的網上敘述最最最詳細的乙個演算法了。可見我才學過幾個演算法qwq 我並不認為我能比網上講的要好 所以 emmm 我就打算解釋一下 不要管這迷一樣的邏輯 先去看看題解hhh 咳咳 等會兒 好了好了 qwq 言歸正傳 這裡的dinic演算法,是對edmonds k...

最小割最大流記錄

經過一系列的學習,明白了一些東西記錄一下備忘 割 是指刪除一些邊,使剩下的網路中沒有增光路,那麼可以得出max flow c s,t 割 為什麼呢?首先我們明白知道最大流一定是根據增光路得到i的,那麼割就是包含增光路的乙個集合,那麼sum c s,t 一定是在在這個 基礎上得到的,也就是割中一定包含...

最大流 最小割定理

割 cut 是網路中頂點的劃分,它把網路中的所有頂點劃分成兩個頂點的集合源點s和匯點t。記為cut s,t 如下圖 源點 s 1 匯點 t 5。框外是容量,框內是流量 如下圖是乙個圖的割。頂點集合s 和t 構成乙個割。如果一條弧的兩個頂點分別屬於頂點集s和t那麼這條弧稱為割cut s,t 的一條割邊...