Skip to content

Commit 8dd0c82

Browse files
author
taotao
committed
添加模板
1 parent 1deda0a commit 8dd0c82

File tree

2 files changed

+236
-3
lines changed

2 files changed

+236
-3
lines changed

Diff for: Graph/Graph.md

+233
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,236 @@ void dfs(int u,int fa){
190190
if(fa == -1 && cl == 1)cut[u] = 0;//根节点
191191
}
192192
```
193+
# 强联通分量分解
194+
```c++
195+
196+
197+
198+
std::vector<int> G[MAX_V];
199+
std::vector<int> rG[MAX_V];
200+
bool vis[MAX_V];
201+
int scc[MAX_V];
202+
std::vector<int> vs;//访问结束时间栈
203+
void add_edge(int u,int v){
204+
G[u].push_back(v);
205+
G[v].push_back(u);
206+
}
207+
void dfs(int u) {
208+
vis[u] = true;
209+
for(int i=0 ; i<G[u].size() ;++i)
210+
if(!vis[G[u][i]])dfs(G[u][i]);
211+
vs.push_back(u);
212+
}
213+
214+
void rdfs(int u,int scc_cnt) {
215+
vis[u] = true;
216+
scc[u] = scc_cnt;
217+
for(int i=0 ; i<rG[u].size() ; ++i)
218+
if(!vis[rG[u][i]])rdfs(rG[u][i]);
219+
}
220+
221+
int Kosaraju(int nv){
222+
int scc_cnt = 0;
223+
memset(vis,false,sizeof(vis));
224+
vs.clear();
225+
for(int i=0 ; i<v ; ++i)
226+
if(!vis[i])dfs(i);
227+
memset(vis,false,sizeof(vis));
228+
for(int i= vs.size()-1 ; i>=0 ; --i)
229+
if(!vis[vs[i]])rdfs(vs[i],++scc_cnt);
230+
return scc_cnt;
231+
}
232+
233+
```
234+
# 网络流
235+
##Dinic
236+
```c++
237+
238+
struct Edge{
239+
int from,to,cap;
240+
Edge(int u,int v,int c = 0):from(u),to(v),cap(c){};
241+
};
242+
243+
//残量网络
244+
void add_edge(int u,int v,int cap){
245+
E.push_back(Egde(u,v,cap));G[u].push_back(E.size()-1);
246+
E.push_back(Edge(v,u,0)); G[v].push_back(E.size()-1);
247+
}
248+
249+
struct Dinic{
250+
std::vector<Edge> E;
251+
std::vector<int> G[MAX_V];
252+
int level[MAX_V],cur[MAX_V];//分层,当前弧;
253+
void bfs(int s){
254+
memset(level,-1,sizeof(level));
255+
queue<int> Q;Q.push(s);
256+
level[s] = 0;
257+
while (!Q.empty()) {
258+
int u = Q.front();Q.pop();
259+
for(int i=0 ; i<G[u].size() ; ++i){
260+
Edge & e = E[G[u][i]];
261+
if(e.cap>0 && level[e.to]<0){
262+
level[e.to] = level[u]+1;
263+
Q.push(e.to);
264+
}
265+
}
266+
}
267+
}
268+
269+
int dfs(int v,int t,int f){
270+
if(v==t || f == 0)return f;
271+
for(int& i = cur[v] ; i<G[v].size() ; ++i){
272+
Edge & e = E[G[v][i]];Edge & rev = E[G[v][i]^1];
273+
if(e.cap>0 && level[v]<level[e.to]){
274+
int a = dfs(e.to,t,min(f,e.cap));
275+
if(a>0){
276+
e.cap-=a;
277+
rev.cap+=a;
278+
return a;
279+
}
280+
}
281+
}
282+
return 0;
283+
}
284+
285+
int max_flow(int s,int t){
286+
int flow = 0;
287+
for(;;){
288+
bfs(s);
289+
if(level[t]<0)break;
290+
memset(cur,0,sizeof(cur));
291+
int f;
292+
while ((f = dfs(s,t,INF))>0) {
293+
flow+=f;
294+
}
295+
}
296+
return flow;
297+
}
298+
}
299+
300+
```
301+
对于上面的建边的方式,e的反向边就是e^1,这个可以自行枚举证明.
302+
303+
##最大流最小切割定理
304+
以下三个条件等价:
305+
1. $f$ 是 $G$ 的最大流.
306+
2. 残存网络中没有增广路
307+
3. $|f| = c(S,T)$ 其中(S,T)是最小切割
308+
309+
###切割
310+
311+
$G$的某个切割 $\{S,T\}$ 是指,将图分为两个不相交的集合,$\{S,T\}$ 的容量为,从 ${S}$ d到 $T$ 的最大容量,即割边的最大容量
312+
313+
#二分图匹配
314+
二分图的一个匹配是指二分图中的一些没有公共顶点的边集,匹配数就是边集的数目,最大匹配是指,使得这样的边集的数目最大.
315+
316+
##算法
317+
当作网络流来处理,将$U 与 V$ 的边改成从 $U 流入 V$ 的一条边,其容量为一.对于这个多元多汇问题,我们只需要连一个超级节点 $S$ 到每一个源点,容量为1,再从每一个汇点连到一个超级汇点 容量也为一,这样这个图的最大流就是最大匹配数.
318+
319+
不过由于是二分图我们可不必真的这样实现
320+
321+
**Code**
322+
```c++
323+
int V;
324+
std::vector<int> G[MAX_V];
325+
bool used[MAX_V];
326+
int match[MAX_V];
327+
328+
bool dfs(int u){
329+
used[u] = true;
330+
for(int i=0 ; i<G[u].size() ; ++i){
331+
int v = G[u][i];int w = match[v];
332+
if(w<0 || !used[w] && dfs(w)){
333+
match[u] = v;match[v] = u;
334+
return true;
335+
}
336+
}
337+
return false;
338+
}
339+
340+
int bipartite_match(){
341+
int res = 0;
342+
memset(match,-1,sizeof(match));
343+
for(int i = 1 ; i<=V ; ++i){
344+
if(match[i]<0){
345+
memset(used,false,sizeof(used));
346+
if(dfs(i))res++;
347+
}
348+
}
349+
return res;
350+
}
351+
352+
void add_edge(int u,int v){
353+
G[u].push_back(v);
354+
G[v].push_back(u);
355+
}
356+
```
357+
358+
#最小费用流
359+
在概念上最小费用流只是在最大流的边上在附加一个费用,即求出从源点到汇点的给定流量的最小费用.
360+
361+
##算法
362+
先从源点找一条到汇点的最短路,然后沿着最短路增广.建图的时候将反向边的费用设为-cost.(退流退费用)
363+
364+
**Code**
365+
366+
```c++
367+
struct Edge{
368+
int from,to,cap,cost;
369+
Edge(int f,int t,int c,int co):from(f),to(t),cap(c),cost(co){}
370+
};
371+
std::vector<Edge> E;
372+
std::vector<int> G[MAX_V];
373+
void add_edge(int u,int v,int cap,int cost){
374+
E.push_back(Edge(u,v,cap,cost));G[u].push_back(E.size()-1);
375+
E.push_back(Edge(v,u,0,-cost)) ;G[v].push_back(E.size()-1);
376+
}
377+
struct MCMF{
378+
int V;
379+
int dist[MAX_V];
380+
int pre_E[MAX_V];//最短路径弧
381+
bool inq[MAX_V];//spfa判断
382+
//未判断负圈
383+
void spfa(int s){
384+
memset(dist,INF,sizeof(dist));
385+
memset(inq,false,sizeof(inq));
386+
queue<int> Q;
387+
Q.push(s);
388+
dist[s] = 0;
389+
inq[s] = true;
390+
pre_E[s] = -1;
391+
while(!Q.empty())
392+
{
393+
int u = Q.front();Q.pop();
394+
inq[u] = false;
395+
for(int i=0 ; i<G[u].size() ; ++i){
396+
Edge &e = E[G[u][i]];
397+
if(e.cap>0&&dist[e.to]>dist[u]+e.cost){
398+
dist[e.to] = dist[u]+e.cost;
399+
pre_E[e.to] = G[u][i];
400+
if(!inq[e.to]){Q.push(e.to);inq[e.to] = true;}
401+
}
402+
}
403+
}
404+
}
405+
406+
int min_cost_flow(int s,int t,int f){
407+
int res = 0;
408+
while (f>0) {
409+
spfa(s);
410+
if(dist[t]==INF)return break;//不能增广
411+
//沿着最短路增广
412+
int d = f;
413+
for(int i = pre_E[t] ; i!=-1 ;i = pre_E[E[i].from])d = min(d,E[i].cap);
414+
f-=d;
415+
res+=d*dist[t];
416+
for(int i = pre_E[t] ; i!=-1 ;i = pre_E[E[i].from]){
417+
E[i].cap-=d;
418+
E[i^1].cap+=d;
419+
}
420+
}
421+
return res;
422+
}
423+
};
424+
425+
```

Diff for: math/莫比乌斯反演笔记.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#基本公式定理
22
$$
3-
\begin{align}
3+
\begin{aligned}
44
n &= \sum_{d\mid n}\phi(d)\\
55
\phi(n)&=\sum_{d\mid n}\mu(d)\frac nd
6-
\end{align}
6+
\end{aligned}
77
$$
88

99
#分块求和
@@ -60,7 +60,7 @@ void phi_table(){
6060
}
6161
for(int j=0 ; j<cnt && i*prime[j]<maxn ; ++j){
6262
prime[i*prime[j]] = 1;
63-
if(i%prime[j])phi[prime[j]*i] = phi[i]*(phi[prime[j]]);
63+
if(i%prime[j])phi[prime[j]*i] = phi[i]*(prime[j]-1);
6464
else {
6565
phi[i*prime[j]]= phi[i]*prime[j];
6666
break;

0 commit comments

Comments
 (0)