===【最大流(最小割)算法】===
最小割就是刪掉權值最小的邊讓源點和匯點分別分在兩個不連通的集合(就是把圖分成兩個集合,保證源點和匯點不連通,可以解決刪掉權值最小的邊刻意讓某些點和另外點孤立,也就是堵住前面點到匯點的去路)
【增廣路EdmondsKarp算法(n*m^2)】n是點數,m是有向邊數
#define rep(i,a,n) for(int i = a; i < n; i++)
#define clc(a,b) memset(a,b,sizeof(a))
#define MAXN 410
#define INF 0x3f3f3f3f
struct EK{
struct E{
int from, to, cap, flow;
E(int a, int b, int c, int d){
from = a, to = b, cap = c, flow = d;
}
};
int a[MAXN], p[MAXN];
vector<int> g[MAXN];
vector<E> edge;
void init(int n)
{
edge.clear();
rep(i,0,n) g[i].clear();
}
void add_edge(int from, int to, int cap)
{
edge.push_back(E(from, to, cap, 0));
edge.push_back(E(to, from, 0, 0));//反向限制爲0
int num = edge.size();
g[from].push_back(num - 2);
g[to].push_back(num - 1);
}
int e_k(int st, int ed)
{
int ans = 0;
while (1)
{
clc(a,0);
queue<int> q;
q.push(st);
a[st] = INF;
while (!q.empty())
{
int x = q.front(); q.pop();
int len = g[x].size();
rep(i,0,len)
{
E& e = edge[g[x][i]];
if (!a[e.to] && e.cap > e.flow)
{
p[e.to] = g[x][i];
a[e.to] = min(a[x], e.cap - e.flow);
q.push(e.to);
}
}
if (a[ed]) break;
}
if (!a[ed]) break;
for (int u = ed; u != st; u = edge[p[u]].from)
{
edge[p[u]].flow += a[ed];
edge[p[u] ^ 1].flow -= a[ed];
}
ans += a[ed];
}
return ans;
}
}ek;
【dinic算法(n^2*m)】
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long LL;
#define MAXN 40010
#define MAXM 400100//記得兩倍 有反向邊
struct Dinic{
struct Edge{
int next, v, cap, flow;
Edge(int a = 0, int b = 0, int c = 0, int d = 0){next = a, v = b, cap = c, flow = d;}
}edge[MAXM];
int head[MAXN], tol, s,t,d[MAXN],cur[MAXN];
bool vis[MAXN];
void init()
{
clc(head,-1);
tol = 0;
}
void add_edge(int u, int v, int cap)
{
edge[tol] = Edge(head[u],v,cap,0);
head[u] = tol++;
edge[tol] = Edge(head[v],u,0,0);
head[v] = tol++;
}
bool bfs()
{
clc(vis,0);
queue<int> q;
q.push(s);
d[s] = 0;
vis[s] = true;
while(!q.empty())
{
int u = q.front();q.pop();
for(int i = head[u]; ~i; i = edge[i].next)
{
Edge& e = edge[i];
if(!vis[e.v] && e.cap > e.flow)
{
vis[e.v] = true;
d[e.v] = d[u]+1;
q.push(e.v);
}
}
}
return vis[t];
}
int dfs(int u, int a)
{
if(u == t || !a) return a;
int flow = 0, f;
for(int i = head[u]; ~i; i = edge[i].next)
{
Edge& e = edge[i];
if(d[u]+1 == d[e.v] && (f = dfs(e.v, min(a,e.cap-e.flow))) > 0)
{
e.flow += f;
edge[i^1].flow -= f;
flow += f;
a -= f;
if(!a) break;
}
}
return flow;
}
int maxflow(int s, int t)
{
this->s = s, this->t = t;
int flow = 0;
while(bfs())
{
clc(cur,0);
flow += dfs(s,INF);
}
return flow;
}
}dinic;
【ISAP 遞歸簡潔版(n^2*m)】
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long LL;
#define MAXN 20
#define MAXM 2010//記得兩倍 有反向邊
struct Isap{
int n,s,t,d[MAXN],num[MAXN];
//n是所有節點數量,s源點,t匯點
struct Edge{//不需要flow,cap即可,最後的flow=原來的cap-現在的cap
int next, v, cap;
Edge(int a = 0, int b = 0, int c = 0){next = a, v = b, cap = c;}
}edge[MAXM];
int head[MAXN], tol;
void init(int n)
{
this->n = n;
clc(num,0);
clc(d,0);
clc(head,-1);
tol = 0;
}
void add_edge(int u, int v, int cap)
{
edge[tol] = Edge(head[u], v, cap);
head[u] = tol++;
edge[tol] = Edge(head[v], u, 0);
head[v] = tol++;
}
int dfs(int u, int a)
{
if(t == u) return a;
int delta, mi = n-1,ans = 0;
for(int i = head[u]; ~i; i = edge[i].next)
{
Edge& e = edge[i];
if(!e.cap) continue;
if(d[e.v]+1 == d[u])
{
delta = dfs(e.v, min(a,e.cap));
if(delta)
{
e.cap -= delta;
edge[i^1].cap += delta;
ans += delta;
a -= delta;
}
else if(d[s] >= n || !a)
return ans;
}
mi = min(mi, d[e.v]);
}
if(!ans)
{
if(!--num[d[u]])
{
d[s] = n;
return 0;
}
num[d[u] = mi+1]++;
}
return ans;
}
int maxflow(int s, int t)
{
this->s = s,this->t = t;
int flow = 0;
num[0] = n;
while(d[s] < n) flow += dfs(s,INF);
return flow;
}
}isap;
【ISAP + BFS初始化 + 棧優化(n^2*m)】
#define rep(i,a,n) for(int i = a; i < n; i++)
#define clc(a,b) memset(a,b,sizeof(a))
#define MAXN 55
#define INF 0x3f3f3f3f
struct ISAP{
struct Edge{
int from, to, cap, flow;
Edge(int a, int b, int c, int d){
from = a, to = b, cap = c, flow = d;
}
};
int p[MAXN]/*可增廣的上一條弧*/, num[MAXN]/*距離標號計數*/, d[MAXN]/*起點到i距離*/,cur[MAXN]/*當前弧下標*/;
int n, s, t;//節點數,邊數,起點,終點
vector<int> g[MAXN];//鄰接表
vector<Edge> edge;
bool vis[MAXN];
void init(int n)
{
this->n = n;
edge.clear();
rep(i,0,n) g[i].clear();
clc(num,0);
clc(cur,0);
}
void add_edge(int from, int to, int cap)
{
edge.push_back(Edge(from,to,cap,0));
edge.push_back(Edge(to,from,0,0));
int m = edge.size();
g[from].push_back(m-2);
g[to].push_back(m-1);
}
int augment()
{
int x = t, a = INF;
while(x != s)
{
Edge& e = edge[p[x]];
a = min(a, e.cap-e.flow);
x = edge[p[x]].from;
}
x = t;
while(x != s)
{
edge[p[x]].flow += a;
edge[p[x]^1].flow -= a;
x = edge[p[x]].from;
}
return a;
}
bool bfs()
{
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(t);
d[t] = 0;
vis[t] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
int sz = g[x].size();
rep(i,0,sz)
{
Edge& e = edge[g[x][i]];
if(!vis[e.to])
{
vis[e.to] = 1;
d[e.to] = d[x]+1;
q.push(e.to);
}
}
}
return vis[s];
}
int maxflow(int s, int t)
{
this->s = s, this->t = t;
int flow = 0;
bfs();//bfs可以不加;需要clc(d,0),並且下面一行換成num[0] = n;
rep(i,0,n) num[d[i]]++;
int x = s;
while(d[s] < n)
{
if(x == t)
{
flow += augment();
x = s;
continue;
}
int ok = 0,sz = g[x].size();
rep(i,cur[x],sz)
{
Edge& e = edge[g[x][i]];
if(e.cap > e.flow && d[x] == d[e.to]+1)
{
ok = 1;
p[e.to] = g[x][i];
cur[x] = i;
x = e.to;
break;
}
}
if(!ok)
{
int sum = n-1;
rep(i,0,sz)
{
Edge& e = edge[g[x][i]];
if(e.cap > e.flow) sum = min(sum,d[e.to]);
}
if(--num[d[x]] == 0) return flow;//gap優化
num[d[x] = sum+1]++;
cur[x] = 0;
if(x != s) x = edge[p[x]].from;
}
}
return flow;
}
}isap;
===【最小費用最大流算法】===
【運用類似EK算法(n*m^2)】
struct MCMF{
int n,m;
struct Edge{
int from, to, cap, flow, cost;
Edge(int a, int b, int c, int d, int e){
from = a, to = b, cap = c, flow = d, cost = e;
}
};
vector<Edge> edge;
vector<int> g[MAXN];
bool inq[MAXN];
int d[MAXN]/*spfa*/, p[MAXN]/*上一條弧*/, a[MAXN]/*可改進量*/;
void init(int n){
this->n = n;
for(int i = 0; i < n; i++) g[i].clear();
edge.clear();
}
void add_edge(int from, int to, int cap, int cost)
{
edge.push_back(Edge(from,to,cap,0,cost));
edge.push_back(Edge(to,from,0,0,-cost));
m = edge.size();
g[from].push_back(m-2);
g[to].push_back(m-1);
}
bool spfa(int s, int t, int& flow, LL& cost)
{
memset(d,0x3f,sizeof(d));
memset(inq,0,sizeof(inq));
d[s] = 0, inq[s] = true, p[s] = 0, a[s] = INF;
queue<int> q;
q.push(s);
while(!q.empty())
{
int u = q.front();q.pop();
inq[u] = false;
for(int i = 0; i < g[u].size(); i++)
{
Edge& e = edge[g[u][i]];
if(e.cap > e.flow && d[e.to] > d[u]+e.cost)
{
d[e.to] = d[u]+e.cost;
p[e.to] = g[u][i];
a[e.to] = min(a[u], e.cap-e.flow);
if(!inq[e.to]) q.push(e.to), inq[e.to] = true;
}
}
}
if(INF == d[t]) return false;
flow += a[t];
cost += (LL)d[t]*(LL)a[t];
for(int u = t; u != s; u = edge[p[u]].from)
{
edge[p[u]].flow += a[t];
edge[p[u]^1].flow -= a[t];
}
return true;
}
//需要保證初始網絡沒有負圈,返回最大流量,cost纔是最小花費
int mincostmaxflow(int s, int t, LL & cost)
{
int flow = 0;
cost = 0;
while(spfa(s,t,flow,cost));
return flow;
}
}mcmf;