Kyopro Library
 
読み取り中…
検索中…
一致する文字列を見つけられません
min_cost_flow.hpp
[詳解]
1#pragma once
2#include "../../../kyopro_library/template.hpp"
3
4/// @brief 最小費用流
5/// @note コスト負の辺を許容する。負の閉路はダメ。
6struct MinCostFlow {
7 /// @brief 辺構造体
8 struct Edge {
9 int from; ///< 始点
10 int to; ///< 終点
11 int rev; ///< 逆辺のインデックス
12 ll cap; ///< 容量
13 ll cost; ///< コスト
14 bool isrev;
15 Edge(int from, int to, ll cap, ll cost, int rev, bool isrev):from(from),to(to),cap(cap),cost(cost),rev(rev),isrev(isrev) {}
16 };
17
18 MinCostFlow(int n) { graph.resize(n),dist.resize(n),pot.resize(n),pv.resize(n),pe.resize(n); }
19
20 /// @brief s -> t に容量 cap, コスト cost の辺を追加する
21 /// @note cost は負でも良い
22 void add_edge(int from, int to, ll cap, ll cost) {
23 graph[from].push_back(Edge(from,to,cap,cost,graph[to].size(),false));
24 graph[to].push_back(Edge(to,from,0,-cost,(int)graph[from].size()-1,true));
25 }
26
27 /// @brief 全ての辺を返す
28 /// @note O(V+E)
29 /// @note 直前に流した flow による残余であることに注意
31 vector<Edge> ret;
32 for(int i=0; i<graph.size(); i++) for(auto &e:graph[i]) if(!e.isrev) ret.push_back(e);
33 return ret;
34 }
35
36 /// @brief s から t へ流量 f の最小費用流のコストを求める
37 /// @brief 流せない場合は INFL を返す
38 /// @note O(FE log V)
39 ll flow(int s, int t, ll f) {
40 int n=graph.size();
41 rpriority_queue<pair<ll,int>> pq;
42 fill(pot.begin(),pot.end(),0);
43 fill(pv.begin(),pv.end(),0);
44 fill(pe.begin(),pe.end(),0);
45 ll ret=0;
46
47 while(f>0) {
48 fill(dist.begin(),dist.end(),INFL);
49 dist[s]=0;
50 pq.push({0,s});
51 while(!pq.empty()) {
52 auto [tmp,now]=pq.top();
53 pq.pop();
54 if(dist[now]<tmp) continue;
55 for(int i=0; i<graph[now].size(); i++) {
56 auto [from,to,rev,cap,cost,isrev]=graph[now][i];
57 ll ncost=dist[now]+cost+pot[now]-pot[to];
58 if(cap>0&&dist[to]>ncost) {
59 dist[to]=ncost,pv[to]=now,pe[to]=i;
60 pq.push({dist[to],to});
61 }
62 }
63 }
64 if(dist[t]==INFL) return INFL;
65 for(int i=0; i<n; i++) pot[i]+=dist[i];
66 ll d=f;
67 for(int v=t; v!=s; v=pv[v]) d=min(d,graph[pv[v]][pe[v]].cap);
68 f-=d,ret+=d*pot[t];
69 for(int v=t; v!=s; v=pv[v]) {
70 auto &e=graph[pv[v]][pe[v]];
71 e.cap-=d,graph[v][e.rev].cap+=d;
72 }
73 }
74
75 return ret;
76 }
77
78private:
79 vector<vector<Edge>> graph;
80 vector<ll> dist,pot; // 距離, ポテンシャル
81 vector<int> pv,pe;
82};
Edge(int from, int to, ll cap, ll cost, int rev, bool isrev)
int rev
逆辺のインデックス
最小費用流
void add_edge(int from, int to, ll cap, ll cost)
s -> t に容量 cap, コスト cost の辺を追加する
vector< Edge > get_edges()
全ての辺を返す
ll flow(int s, int t, ll f)
s から t へ流量 f の最小費用流のコストを求める
const ll INFL
Definition template.hpp:13