主要用來複習一下自己之前學過的網路流。
因為當時都是直接抄的題解,莫得印象。所以寫篇部落格加強記憶。
先分析題目。
比較明顯,如果我們用網路流的思路去分析這個問題。將會將每個單位和每個餐桌都看做點。然後由於每個單位的人理論上可以坐在任意餐桌,同時對於乙個餐桌乙個單位只能有乙個人。所以每個單位向每個餐桌連一條容量為\(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 的一條割邊...