mysql最小费用最大流问题_最小费用最大流问题(示例代码)

费用流

假设每条边除了有一个容量限制外,还有一个单位流量所需的费用(cost)。该网络中花费最小的最大流称为最小费用最大流,即总流量最大的情况下,总费用最小的流。

和 Edmonds-Karp 算法类似,但每次用 Bellman-Ford 算法而非 BFS 找增广路。只要初始流是该流量下的最小费用可行流,每次增广后的新流都是新流量下的最小费用流。

Bellman-Ford版

如何用优先队列代替Bellman-Ford中的普通队列就是SPFA版。

structEdge{int from, to, cap, flow, cost;

Edge(int u, int v, int c, int f, int w):from(u), to(v), cap(c), flow(f), cost(w){}

};structMCMF

{intn, m;

vectoredges;

vectorG[maxn];int inq[maxn]; //是否在队列中

int d[maxn]; //Bellman-Ford

int p[maxn]; //上一条弧

int a[maxn]; //可改进量

void init(intn)

{this->n =n;for(int i = 0;i < n;i++) G[i].clear();

edges.clear();

}void AddEdge(int from, int to, int cap, intcost)

{

edges.push_back(Edge(from, to, cap, 0, cost)); //有向边

edges.push_back(Edge(to ,from, 0, 0, -cost));

m=edges.size();

G[from].push_back(m-2);

G[to].push_back(m-1);

}bool BellmanFord(int s, int t, int& flow, int&cost)

{for(int i = 0;i < n;i++) d[i] =INF;

memset(inq,0, sizeof(inq));

d[s]= 0; inq[s] =1; p[s] = 0;a[s] =INF;

queueQ;;

Q.push(s);while(!Q.empty())

{int u =Q.front(); Q.pop();

inq[u]= 0;for(int i = 0;i < G[u].size();i++)

{

Edge& e =edges[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] = 1;}

}

}

}if(d[t] == INF) return false;

flow+=a[t];

cost+= d[t] *a[t];for(int u = t;u != s;u = edges[p[u]].from)

{

edges[p[u]].flow+=a[t];

edges[p[u]^1].flow -=a[t];

}return true;

}//需要保证初始网络中没有负权圈

int MaxcostMaxflow(int s, int t, int&cost)

{int flow = 0; cost = 0;while(BellmanFord(s, t, flow, cost));returnflow;

}

}mcmf;

Dijkstra版

可以采用加入“势函数”后的Dijkstra算法。因为对于每一条边 $e=(u, v)$,有如下事实成立:$h(v) \leq h(u)+e.cost$ (其中 $h(u)$ 表示 $s$ 到 $u$ 的最短距离),因此令 $dis[v] = dis[u] + e.cost + h[u] - h[v]$,那么所有的 $dist$ 值必然大于等于0,这样就能用 $Dijkstra$ 求解了。

下面代码中用了一个优先队列,每次优先队列列出 $dist$ 值小的元素。

整个算法的时间复杂度为 $O(FElogV)$($F$ 是流量,$E$ 是边数,$V$ 是顶点数)。

structedge {intto, capacity, cost, rev;

edge() {}

edge(int to, int _capacity, int _cost, int_rev) :to(to), capacity(_capacity), cost(_cost), rev(_rev) {}

};structMin_Cost_Max_Flow {int V, H[maxn + 5], dis[maxn + 5], PreV[maxn + 5], PreE[maxn + 5];

vector G[maxn + 5];//调用前初始化

void Init(intn) {

V=n;for (int i = 0; i <= V; ++i)G[i].clear();

}//加边

void Add_Edge(int from, int to, int cap, intcost) {

G[from].push_back(edge(to, cap, cost, G[to].size()));

G[to].push_back(edge(from, 0, -cost, G[from].size() - 1));

}//flow是自己传进去的变量,就是最后的最大流,返回的是最小费用

int Min_cost_max_flow(int s, int t, int f, int&flow) {int res = 0; fill(H, H + 1 + V, 0);while(f) {

priority_queue, vector>, greater> >q;

fill(dis, dis+ 1 +V, INF);

dis[s]= 0; q.push(pair(0, s));while (!q.empty()) {

pair now =q.top(); q.pop();int v =now.second;if (dis[v] < now.first)continue;for (int i = 0; i < G[v].size(); ++i) {

edge& e =G[v][i];if (e.capacity > 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];

PreV[e.to]=v;

PreE[e.to]=i;

q.push(pair(dis[e.to], e.to));

}

}

}if (dis[t] == INF)break;for (int i = 0; i <= V; ++i)H[i] +=dis[i];int d =f;for (int v = t; v != s; v = PreV[v])d =min(d, G[PreV[v]][PreE[v]].capacity);

f-= d; flow += d; res += d*H[t];for (int v = t; v != s; v =PreV[v]) {

edge& e =G[PreV[v]][PreE[v]];

e.capacity-=d;

G[v][e.rev].capacity+=d;

}

}returnres;

}int Max_cost_max_flow(int s, int t, int f, int&flow) {int res = 0;

fill(H, H+ 1 + V, 0);while(f) {

priority_queue>q;

fill(dis, dis+ 1 + V, -INF);

dis[s]= 0;

q.push(pair(0, s));while (!q.empty()) {

pair now =q.top(); q.pop();int v =now.second;if (dis[v] > now.first)continue;for (int i = 0; i < G[v].size(); ++i) {

edge& e =G[v][i];if (e.capacity > 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];

PreV[e.to]=v;

PreE[e.to]=i;

q.push(pair(dis[e.to], e.to));

}

}

}if (dis[t] == -INF)break;for (int i = 0; i <= V; ++i)H[i] +=dis[i];int d =f;for (int v = t; v != s; v = PreV[v])d =min(d, G[PreV[v]][PreE[v]].capacity);

f-= d; flow +=d;

res+= d*H[t];for (int v = t; v != s; v =PreV[v]) {

edge& e =G[PreV[v]][PreE[v]];

e.capacity-=d;

G[v][e.rev].capacity+=d;

}

}returnres;

}

}mcmf;

注:

如果是求最大费用,只需加边是边权取反,最终费用也取反

第一种可能被卡时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值