日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

算法学习:费用流

發布時間:2025/7/14 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法学习:费用流 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【前置知識】

最大流

?


【問題描述】

給定一個圖,圖上的邊每條邊有流量,流量有費用,

求在流量為 F 時費用的最小值

?

?


【分析思路】

求費用最小,我們很容易想到求最短路徑,我們只需要將費用看作代價然后求最短路不久能求出來最小費用了嘛

但是,問題來了

我們又如何能夠在求最小費用的同時,滿足流量最終為F的條件

在最大流中提到,每次增廣都是在殘余網絡中通過詢問 s 至 t 的殘余網絡進行增廣

所以,我們每次在殘余網絡上求最短路就可以了

這里注意,殘余網絡中的反向邊的費用應該時原邊費用的相反數

這樣在計算的時候,才能保證過程是可逆的

【證明】

在殘余網絡上求最短路是最小費用

證:

1? 設有? f 為以以上方式求出的結果, 設? f ’ 和 f 流量相同,但是費用更少

因為? f ‘ - f 的流量流入流出為 0,所以他是成環的

又因為 f ’ - f 的費用是負的,所以在這些環中,存在負環

結論:f 是最小費用流? ?<====>? 殘余網絡中沒有負環

(因為負環顯而易見的能夠通過轉圈減少費用)

2??對于流量為 0 的流 f0 ,其殘余網絡為原圖,原圖沒有負環,則f0 就是最小費用流

設流量為i 的流 fi 是最小流,并且下一步我們求得流量為 i + 1的流 f[i+1],按照方法,f[ i + 1 ] - f [ i ]就是 f[ i ]對應的參余網絡中 s 到 t 的最短路

假設 f [ i + 1 ] ' 的費用比 f [ i + 1 ]還小,則 f [ i + 1 ] '- f [ i ] 的費用比f[ i + 1 ] - f [ i ] 還小,所以f [ i + 1 ] '- f [ i ] 中有負環

所以這與假設矛盾,于是可以證明這種方法是正確的

?

?


?

【代碼】

(基本上就是在最大流的基礎上稍微改進了下)

// luogu-judger-enable-o2 #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #include<cstring> #define ll long long using namespace std; const int MAXN = 50010; const int MAXM = 100010; const ll INF = (1ll << 62) - 1; typedef pair<int, int> P; struct note {int to;int nt;int rev;ll cost;ll cal; }; struct edge {note arr[MAXM];int st[MAXN];ll dis[MAXN];ll h[MAXN];int cur[MAXN];int depth[MAXN];int pre[MAXN];int pree[MAXN];int top;int n, m, s, t;edge(){memset(st, -1, sizeof(st));memset(depth, -1, sizeof(depth));memset(dis, -1, sizeof(dis));top = 0;}void read(){top = 0;scanf("%d%d%d%d", &n, &m, &s, &t);for (int i = 1; i <= m; i++){int x, y;ll z,c;scanf("%d%d%lld%lld", &x, &y, &z,&c);add(x, y, z,c);}}bool dep(){queue<int> q;q.push(s);memset(depth, -1, sizeof(depth));depth[s] = 0;while (!q.empty()){int v = q.front(); q.pop();for (int i = st[v]; i != -1; i = arr[i].nt){int to = arr[i].to;if (!arr[i].cal)continue;if (depth[to] != -1)continue;depth[to] = depth[v] + 1;q.push(to);}}return (depth[t] != -1);}void add(int x, int y, ll z,ll c){top++; arr[top] = { y,st[x],top + 1,c,z }; st[x] = top;top++; arr[top] = { x,st[y],top - 1,-c,0 }; st[y] = top;}ll dfs(int now, ll val){if (now == t || !val)return val;ll flow = 0;for (int& i = cur[now]; i != -1; i = arr[i].nt){int to = arr[i].to;if (depth[to] != depth[now] + 1)continue;ll f = dfs(to, min(arr[i].cal, val));if (!f || !arr[i].cal)continue;flow += f;arr[i].cal -= f;arr[arr[i].rev].cal += f;val -= f;if (!val)return flow;}return flow;}ll dinic(){ll flow = 0;ll f;while (dep()){for (int i = 1; i <= n; i++)cur[i] = st[i];while (f = dfs(s, INF))flow += f;}return flow;}ll min_cost(ll f){ll res = 0;while (f > 0){fill(dis, dis + 1 + n, INF);priority_queue<P, vector<P>, greater<P>> q;dis[s] = 0;q.push(P(0, s));while (!q.empty()){P p = q.top(); q.pop();int v = p.second;if (dis[v] < p.first) continue;for (int i = st[v]; i != -1; i = arr[i].nt){note &e = arr[i];if (e.cal > 0 && dis[e.to] > dis[v] + e.cost + h[v] - h[e.to]){dis[e.to] = dis[v] + e.cost + h[v] - h[e.to];pre[e.to] = v;pree[e.to] = i;q.push(P(dis[e.to],e.to));}}}if (dis[t] == INF) return -1;for (int i = 0; i <= n; i++)h[i] += dis[i];ll d = f;//printf("2\n");for (int i = t; i != s; i = pre[i]){d = min(d, arr[pree[i]].cal);}f -= d;res += d * h[t];for (int i = t; i != s; i = pre[i]){arr[pree[i]].cal -= d;;int rev = arr[pree[i]].rev;arr[rev].cal += d;}//printf("3\n"); }return res;} }; edge road; edge tmp; int main() {int T;road.read();tmp = road;ll f = tmp.dinic();printf("%lld ", f);printf("%lld", road.min_cost(f));return 0; } View Code

?

注意:因為求最大流之后網絡會發生變化,所以需要把最開始的原圖記錄下來

  ? ?費用流的求取也要在原圖上進行

?

轉載于:https://www.cnblogs.com/rentu/p/11323530.html

總結

以上是生活随笔為你收集整理的算法学习:费用流的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。