费用流 Dijkstra 原始对偶方法(primal-dual method)
简单叙述用Dijkstra求费用流
Dijkstra不能求有负权边的最短路。
类似于Johnson算法,我们也可以设计一个势函数,以满足在与原图等价的新图中的边权非负。
但是这个算法并不能处理有负圈的情况(可能需要消圈算法)。
对网络\(G\)中的每一个点设置一个势函数\(h(u)\),在任意残留网络G'的任意边\((u, v)\)都需要满足\(w_{u, v} + h(u) - h(v) \ge 0\)。
令图G的对偶图(不知道能不能这么说)为\(G'\),其对应的边\((u, v)\)的权值为\(w'_{u, v} = w_{u, v} + h(u) + h(v)\)
对于原图中的任意一条路径\((u_1, u_2, \cdots, u_k)\),它在\(G\)中的权值为\(w_{u_1, u_2} + w_{u_2, u_3} + \cdots + w_{u_{k - 1}, u_k}\),在\(G'\)中的权值为
\(w'_{u_1, u_2} + w'_{u_2, u_3} + \cdots + w'_{u_{k - 1}, u_k}\)
\(= w_{u_1, u_2} + w_{u_2, u_3} + \cdots + w_{u_{k - 1}, u_k} + h(u_1) - h(u_2) + h(u_2) - h(u_3) + \cdots + h(u_{k - 1}) - h(u_k)\)
\(= w_{u_1, u_2} + w_{u_2, u_3} + \cdots + w_{u_{k - 1}, u_k} + h(u_1) - h(u_k)\)
所以,我们在\(G'\)求出的路径都可以对应到\(G\)上,令\(dist_{u, v}\)为图\(G\)点\(u\)到点\(v\)的最短路径,\(dist'_{u, v}\)为图\(G'\)点\(u\)到点\(v\)的最短路径,显然有\(dist_{u, v} = dist'_{u, v} - h(u) + h(v)\)
所以我们只需要求\(G'\)的最短路径,就能对应回原图的最短路径。
若网络\(G\)初始边权非负,我们可令\(h(u) = 0\)
否则我们令\(h(u) = dist_{s, u}\),这个可以用Bellman-Ford算法解决。(这与Johnson算法是一模一样的)
我们考虑怎么维护势函数\(h(u)\)。
令网路\(G\)上\(dist_{s, u} = d_u\),网路\(G'\)上\(dist'_{s, u} = d'_u\)
令残余网路\(G'\)上新的势函数为\(h'(u)\)。
对于残余网络上的一条边\((u, v)\),有两种可能:
\((u, v) \in G\),那么有\(d_u + w_{u, v} + h(u) - h(v) \ge d_v\)
移项得\(w_{u, v} + (h(u) + d_u) - (h(v) + d_v) \ge 0\)
\((u, v) \in G\),那么\((v, u) \in G的增广路\),就有\(d_v + w_{v, u} + h(v) - h(u) = d_u\)
移项得\(-w_{v, u} + (h(u) + d_u) - (h(v) - d_v) = 0\)
由\(w_{u, v} = -w_{v, u}\)可得\(w_{u, v} + (h(u) + d_u) - (h(v) - d_v) = 0\)
也就有\(w_{u, v} + (h(u) + d_u) - (h(v) - d_v) \ge 0\)
所以我们不妨令\(h'(u) = h(u) + d_u\),这就维护好了势函数\(h(u)\)
单路增广
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
#define fi first
#define se second
#define mp make_pair
const int N = 5005, M = 50005;
const int INF = ~0u >> 1;
int n, m, s, t;
int tot = -1, head[N];
struct Edge {
int p, nxt, c, w;
Edge(int p = 0, int nxt = 0, int c = 0, int w = 0) : p(p), nxt(nxt), c(c), w(w) {}
} edge[M * 2];
inline void Add_Edge(int u, int v, int c, int w) {
edge[++tot] = Edge(v, head[u], c, w);
head[u] = tot;
return;
}
int h[N], d[N], dc[N], pr[N];
priority_queue<PII> pq;
bool Dijkstra(int s, int t, int &mf, int &mc) {
fill(d + 1, d + n + 1, INF);
dc[s] = INF;
d[s] = 0;
pr[s] = -1;
pq.push(mp(0, s));
while (!pq.empty()) {
PII cur = pq.top();
pq.pop();
int u = cur.se;
if (-cur.fi > d[u]) continue;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].p, c = edge[i].c, w = edge[i].w + h[u] - h[v];
if (!c) continue;
if (d[v] > d[u] + w) {
d[v] = d[u] + w;
pr[v] = i;
dc[v] = min(dc[u], c);
pq.push(mp(-d[v], v));
}
}
}
if (d[t] == INF) return 0;
for (int i = 1; i <= n; ++i)
if (d[i] < INF) h[i] += d[i];
int c = dc[t];
mf += c;
mc += c * h[t];
for (int x = t; ~pr[x]; x = edge[pr[x] ^ 1].p) {
edge[pr[x]].c -= c;
edge[pr[x] ^ 1].c += c;
}
return 1;
}
int main() {
scanf("%d%d%d%d", &n, &m, &s, &t);
memset(head, -1, sizeof(head));
for (int i = 1; i <= m; ++i) {
int u, v, c, w;
scanf("%d%d%d%d", &u, &v, &c, &w);
Add_Edge(u, v, c, w);
Add_Edge(v, u, 0, -w);
}
int mf = 0, mc = 0;
while (Dijkstra(s, t, mf, mc));
printf("%d %d\n", mf, mc);
return 0;
}
多路增广(复杂度不变)
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
#define fi first
#define se second
#define mp make_pair
const int N = 5005, M = 50005;
const int INF = ~0u >> 1;
int n, m, s, t;
int tot = -1, head[N], cur[N];
struct Edge {
int p, nxt, c, w;
Edge(int p = 0, int nxt = 0, int c = 0, int w = 0) : p(p), nxt(nxt), c(c), w(w) {}
} edge[M * 2];
inline void Add_Edge(int u, int v, int c, int w) {
edge[++tot] = Edge(v, head[u], c, w);
head[u] = tot;
return;
}
int h[N], d[N];
priority_queue<PII> pq;
bool Dijkstra(int s, int t) {
fill(d + 1, d + n + 1, INF);
pq.push(mp(d[s] = 0, s));
while (!pq.empty()) {
PII cur = pq.top();
pq.pop();
int u = cur.se;
if (-cur.fi > d[u]) continue;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].p, c = edge[i].c, w = edge[i].w + h[u] - h[v];
if (c && d[v] > d[u] + w) pq.push(mp(-(d[v] = d[u] + w), v));
}
}
return d[t] < INF;
}
int v[N];
int DFS(int u, int c, int t) {
if (u == t) return c;
int r = c;
v[u] = 1;
for (int &i = cur[u]; ~i && r; i = edge[i].nxt) {
int v = edge[i].p, c = edge[i].c, w = edge[i].w + h[u] - h[v];
if (!::v[v] && c && d[u] + w == d[v]) {
int x = DFS(v, min(r, c), t);
r -= x;
edge[i].c -= x;
edge[i ^ 1].c += x;
}
}
v[u] = 0;
return c - r;
}
int main() {
scanf("%d%d%d%d", &n, &m, &s, &t);
memset(head, -1, sizeof(head));
for (int i = 1; i <= m; ++i) {
int u, v, c, w;
scanf("%d%d%d%d", &u, &v, &c, &w);
Add_Edge(u, v, c, w);
Add_Edge(v, u, 0, -w);
}
int mf = 0, mc = 0;
while (Dijkstra(s, t)) {
memcpy(cur, head, sizeof(cur));
int c = DFS(s, INF, t);
for (int i = 1; i <= n; ++i)
if (d[i] < INF) h[i] += d[i];
mf += c;
mc += c * h[t];
}
printf("%d %d\n", mf, mc);
return 0;
}
费用流 Dijkstra 原始对偶方法(primal-dual method)的更多相关文章
- 【BZOJ4842】[Neerc2016]Delight for a Cat 线性规划+费用流
[BZOJ4842][Neerc2016]Delight for a Cat Description ls是一个特别堕落的小朋友,对于n个连续的小时,他将要么睡觉要么打隔膜,一个小时内他不能既睡觉也打 ...
- HDU 6611 K Subsequence(Dijkstra优化费用流 模板)题解
题意: 有\(n\)个数\(a_1\cdots a_n\),现要你给出\(k\)个不相交的非降子序列,使得和最大. 思路: 费用流建图,每个点拆点,费用为\(-a[i]\),然后和源点连边,和后面非降 ...
- UVA 10806 Dijkstra, Dijkstra.(费用流)
n个点的无向带权图,求1->n的最短往返路径,不走重复边. 这里涉及到一个知识点:求无向图上s->t的最短路,其实就是费用流. 而求1->n最短往返路径呢?增加源点s,由s到1加弧, ...
- 网络流板子/费用流板子 2018南京I题+2016青岛G题
2018南京I题: dinic,链式前向星,数组队列,当前弧优化,不memset全部数组,抛弃满流点,bfs只找一条增广路,每次多路增广 #include <bits/stdc++.h> ...
- 【P2405】方格取数问题加强版(费用流)
考虑如何建图.还是老样子先拆点,然后把每两个点之间连接两条边,一条流量为1,费用为-点权,处理是否走这个点.一条流量无限,没有费用,因为哪怕一个点选过了,它的地方还是可以重复走过去的. 然后把经由一个 ...
- 洛谷 1004 dp或最大费用流
思路: dp方法: 设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值. 则转移方程为 dp[i][j][k][l]=max(dp[i-1][j][k-1][l ...
- 【BZOJ-3638&3272&3267&3502】k-Maximum Subsequence Sum 费用流构图 + 线段树手动增广
3638: Cf172 k-Maximum Subsequence Sum Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 174 Solved: 9 ...
- [bzoj4514]数字配对[费用流]
今年SDOI的题,看到他们在做,看到过了一百多个人,然后就被虐惨啦... 果然考试的时候还是打不了高端算法,调了...几天 默默地yy了一个费用流构图: 源连所有点,配对的点连啊,所有点连汇... 后 ...
- 【wikioi】1033 蚯蚓的游戏问题(费用流)
http://wikioi.com/problem/1033/ 这题也是很水的费用流啊,同之前那题一样,拆点然后建边,容量为1,费用为点权.然后建个源连第一行每个点,容量为1,费用为0,然后最后一行每 ...
随机推荐
- rsync启动脚本
rsync启动脚本 01 #!/bin/bash www.ahlinux.com 02 # 03 # rsyncd This shell script takes care of star ...
- python一些包
jieba结巴 github上已经够详细了https://github.com/vinta/awesome-python
- 数据科学中的R和Python: 30个免费数据资源网站
1 政府数据 Data.gov:这是美国政府收集的数据资源.声称有多达40万个数据集,包括了原始数据和地理空间格式数据.使用这些数据集需要注意的是:你要进行必要的清理工作,因为许多数据是字符型的或是有 ...
- 锋利的jQuery(第二版) 初读笔记
window.onload(): 必须等待网页中所有的内容加载完毕后(包括图片)才能执行. $(document).ready(): 网页中所有DOM结构绘制完毕后就执行,可能DOM元素关联的东西并没 ...
- java:struts框架4(Ajax)
1.Ajax: 先导入jar包: struts.xml: <?xml version="1.0" encoding="UTF-8"?> <!D ...
- MyBatis框架原理3:缓存
上一篇[MyBatis框架原理2:SqlSession运行过程][1]介绍了MyBatis的工作流程,其中涉及到了MyBatis缓存的使用,首先回顾一下工作流程图: 如果开启了二级缓存,数据查询执行过 ...
- Unity 动画属性
在动画的使用上使用不当的设置往往会造成不可预料的结果. 首先,如果动画自身可以驱动物体移动,那么在Animator组件上必须选择apply root motion,物体的动画位移才能生效,否则动画只能 ...
- python 一周总结
从7月27前就开始了Djangoj框架的学习到今天一个项目实战已经过了一半了, django给我的感觉就像一个成熟的mov 首先是是数据模型层,Django已经成熟的加入了很多的数据模型供我们所使用 ...
- 【VS开发】使用 NuGet 管理项目库
NuGet 使用 NuGet 管理项目库 Phil Haack 无论多么努力,Microsoft 也没办法提供开发人员所需要的每一个库. 虽然 Microsoft 在全球的员工人数接近 90,000, ...
- oracle truncate表 恢复操作
truncate恢复表 1.创建测试用表 conn elan/elan create table haha as select * from dba_users; 2.查询表数据 ) from hah ...