日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

算法学习:费用流

發(fā)布時(shí)間:2025/7/14 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法学习:费用流 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【前置知識(shí)】

最大流

?


【問(wèn)題描述】

給定一個(gè)圖,圖上的邊每條邊有流量,流量有費(fèi)用,

求在流量為 F 時(shí)費(fèi)用的最小值

?

?


【分析思路】

求費(fèi)用最小,我們很容易想到求最短路徑,我們只需要將費(fèi)用看作代價(jià)然后求最短路不久能求出來(lái)最小費(fèi)用了嘛

但是,問(wèn)題來(lái)了

我們又如何能夠在求最小費(fèi)用的同時(shí),滿足流量最終為F的條件

在最大流中提到,每次增廣都是在殘余網(wǎng)絡(luò)中通過(guò)詢問(wèn) s 至 t 的殘余網(wǎng)絡(luò)進(jìn)行增廣

所以,我們每次在殘余網(wǎng)絡(luò)上求最短路就可以了

這里注意,殘余網(wǎng)絡(luò)中的反向邊的費(fèi)用應(yīng)該時(shí)原邊費(fèi)用的相反數(shù)

這樣在計(jì)算的時(shí)候,才能保證過(guò)程是可逆的

【證明】

在殘余網(wǎng)絡(luò)上求最短路是最小費(fèi)用

證:

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

因?yàn)? f ‘ - f 的流量流入流出為 0,所以他是成環(huán)的

又因?yàn)?f ’ - f 的費(fèi)用是負(fù)的,所以在這些環(huán)中,存在負(fù)環(huán)

結(jié)論:f 是最小費(fèi)用流? ?<====>? 殘余網(wǎng)絡(luò)中沒(méi)有負(fù)環(huán)

(因?yàn)樨?fù)環(huán)顯而易見(jiàn)的能夠通過(guò)轉(zhuǎn)圈減少費(fèi)用)

2??對(duì)于流量為 0 的流 f0 ,其殘余網(wǎng)絡(luò)為原圖,原圖沒(méi)有負(fù)環(huán),則f0 就是最小費(fèi)用流

設(shè)流量為i 的流 fi 是最小流,并且下一步我們求得流量為 i + 1的流 f[i+1],按照方法,f[ i + 1 ] - f [ i ]就是 f[ i ]對(duì)應(yīng)的參余網(wǎng)絡(luò)中 s 到 t 的最短路

假設(shè) f [ i + 1 ] ' 的費(fèi)用比 f [ i + 1 ]還小,則 f [ i + 1 ] '- f [ i ] 的費(fèi)用比f(wàn)[ i + 1 ] - f [ i ] 還小,所以f [ i + 1 ] '- f [ i ] 中有負(fù)環(huán)

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

?

?


?

【代碼】

(基本上就是在最大流的基礎(chǔ)上稍微改進(jìn)了下)

// 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

?

注意:因?yàn)榍笞畲罅髦缶W(wǎng)絡(luò)會(huì)發(fā)生變化,所以需要把最開(kāi)始的原圖記錄下來(lái)

  ? ?費(fèi)用流的求取也要在原圖上進(jìn)行

?

轉(zhuǎn)載于:https://www.cnblogs.com/rentu/p/11323530.html

總結(jié)

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

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。