Java 新記憶體(cache)模型解析
阿新 • • 發佈:2022-03-31
網路流
演算法進階課(試聽課)—— 網路流的基本概念_嗶哩嗶哩_bilibili
概念:
源點:只有流出去的點
匯點:只有流進來的點
流量:一條邊上流過的流量
容量:一條邊上可供流過的最大流量
殘量:一條邊上的容量-流量
流:指滿足網路流的一種方案。
1,在一個有向圖中,有n個點和m條邊。有一個源點,和一個匯點,每條邊有一個容量限制。
2,每條邊的流量<=容量。
3,源點流出量=匯點流入量,其餘各點流入量和流出量相等
當不存在增廣路時,當前流為最大流。
P3376 【模板】網路最大流 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)
EK
演算法:
採用連事前向星的方式儲存。
struct EDGE { int v, power, nxt; }; EDGE edge[10004]; int tot = 0, head[202]; int n, m, s, t, book[202], pre[202]; int d[202], M = 2147483647; int bfs(); void add(int u, int v, int w); void EK(); int main() { cin >> n >> m >> s >> t; int x, y, z; for (int i = 1; i <= n; i++) head[i] = -1; for (int i = 1; i <= m; i++) { cin >> x >> y >> z; add(x, y, z); add(x,y,0); } EK(); return 0; } void add(int u, int v, int w) { edge[tot].v = v, edge[tot].power = w, edge[tot].nxt = head[u], head[u] = tot, tot++; } void EK() { long long ans = 0; while (bfs()) { ans = ans + d[t]; for (int i = t; i != s; i = edge[pre[i] ^ 1].v) { edge[pre[i]].power -= d[t]; edge[pre[i] ^ 1].power += d[t]; } } cout << ans; } int bfs()//bfs尋找增廣路 { queue<int> q; memset(book, 0, sizeof(book)); memset(pre, 0, sizeof(pre)); memset(d, 0, sizeof(d)); q.push(s); book[s] = 1; d[s] = M; while (!q.empty()) { int now = q.front(); q.pop(); for (int i = head[now]; i != -1; i = edge[i].nxt) { int v = edge[i].v, w = edge[i].power; if (book[v] == 0 && w > 0) { q.push(v); book[v] = 1; d[v] = min(d[now], w); pre[v] = i; if (v == t) return 1; } } } return 0; }
dinic
演算法:
對EK演算法進行一些優化。
EK演算法每次bfs只能找到一條增廣路,
dinic演算法利用分層圖的原理,使用bfs將n個點分層,在使用dfs一次可以找到多條增廣路。
#include<iostream> #include<cmath> #include<string> #include<deque> #include<cstring> #include<algorithm> #include<queue> using namespace std; struct EDGE { int v, power, nxt; }; EDGE edge[10004]; int tot = 0, head[202], n, m, s, t, dep[202], M = 2147483647; long long ans; void add(int x, int y, int z); void dinic(); int bfs(); int dfs(int x, int mi); int main() { cin >> n >> m >> s >> t; int x, y, z; memset(head, -1, sizeof(head)); for (int i = 1; i <= m; i++) { cin >> x >> y >> z; add(x, y, z); add(y,x,0); } dinic(); return 0; } void add(int x, int y, int z) { edge[tot].v = y; edge[tot].power = z; edge[tot].nxt = head[x]; head[x] = tot; tot++; } void dinic() { long long ans = 0; while (bfs()) { ans = ans + dfs(s, M); } cout << ans; } int bfs() { memset(dep, 0, sizeof(dep)); dep[s] = 1; queue<int> q; q.push(s); while (!q.empty()) { int now = q.front(); q.pop(); for (int i = head[now]; i != -1; i = edge[i].nxt) { if (edge[i].power > 0 && dep[edge[i].v] == 0) { dep[edge[i].v] = dep[now] + 1; q.push(edge[i].v); } } } if (dep[t] == 0) return 0; return 1; } int dfs(int x, int mi)//x表示當前節點,mi表示節點s到節點x的所有路徑的最小容量 { if (x == t) return mi; int out = 0; for (int i = head[x]; i != -1; i = edge[i].nxt) { if (dep[edge[i].v] == dep[x] + 1 && edge[i].power > 0) { int d = dfs(edge[i].v, min(mi, edge[i].power)); mi -= d; out += d; edge[i].power -= d; edge[i ^ 1].power += d; } } if (out == 0) dep[x] = 0; return out; }
最小費用最大流
P3381 【模板】最小費用最大流 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)
和網路流類似。每條邊再增加一個量:費用。
求網路流最大時的最小費用。
使用EK演算法+SPFA優化可以解決。
EK演算法求網路流時,求的是一條增廣路,而不是花費最小的路。
使用SPFA代替bfs可以得到花費最小的增廣路。
#include<iostream>
#include<cmath>
#include<string>
#include<deque>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int Maxm = 5e4 + 4;
const int Maxn = 5e3 + 3;
struct EDGE
{
int v, power, nxt, cost;
};
EDGE edge[Maxm * 2];
int tot, n, m, s, t, head[Maxn], Max = 2147483647, dis[Maxn], book[Maxn], flow[Maxn];
int pre[Maxn];
void add(int x, int y, int w, int c);
void MCMF();
int SPFA();
int main()
{
cin >> n >> m >> s >> t;
int x, y, w, c;
memset(head, -1, sizeof(head));
for (int i = 1; i <= m; i++)
{
cin >> x >> y >> w >> c;
add(x, y, w, c);
add(y, x, 0, -c);
}
MCMF();
return 0;
}
void add(int x, int y, int w, int c)
{
edge[tot].v = y; edge[tot].power = w; edge[tot].cost = c; edge[tot].nxt = head[x]; head[x] = tot; tot++;
}
void MCMF()
{
int ansflow = 0, anscost = 0;
while (SPFA())
{
ansflow += flow[t];
anscost += flow[t] * dis[t];
for (int i = t; i != s; i = edge[pre[i] ^ 1].v)
{
edge[pre[i]].power -= flow[t];
edge[pre[i] ^ 1].power += flow[t];
}
}
cout << ansflow << " " << anscost;
}
int SPFA()
{
queue<int> q;
memset(book, 0, sizeof(book));
memset(flow, 0, sizeof(flow));
for (int i = 1; i <= n; i++)
dis[i] = Max;
q.push(s);
book[s] = 1;
flow[s] = Max;
dis[s] = 0;
//dis[i]表示s到i的最短路徑,(費用之和最小)
while (!q.empty())
{
int now = q.front(); q.pop();
book[now] = 0;
for (int i = head[now]; i != -1; i = edge[i].nxt)
{
int v = edge[i].v;
if (edge[i].power > 0 && dis[v] > dis[now] + edge[i].cost)
{
dis[v] = dis[now] + edge[i].cost;
flow[v] = min(flow[now], edge[i].power);
pre[v] = i;
if (book[v] == 0)
book[v] = 1, q.push(v);
}
}
}
if (dis[t] == Max)
return 0;
return 1;
}