最大流算法 ISAP 模板 和 Dinic模板
ISAP
// UVa11248 Frequency Hopping:使用ISAP算法,加优化
// Rujia Liu struct Edge {
int from, to, cap, flow;
}; struct ISAP {
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[maxn]; // BFS使用
int d[maxn]; // 从起点到i的距离
int cur[maxn]; // 当前弧指针
int p[maxn]; // 可增广路上的上一条弧
int num[maxn]; // 距离标号计数 void AddEdge(int from, int to, int cap) {
edges.push_back((Edge){from, to, cap, });
edges.push_back((Edge){to, from, , });
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS() {
memset(vis, , sizeof(vis));
queue<int> Q;
Q.push(t);
vis[t] = ;
d[t] = ;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for(int i = ; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]^];///因为t本来就是最后一个结点,一般最后都是反向边的?
if(!vis[e.from] && e.cap > e.flow) {
vis[e.from] = ;
d[e.from] = d[x] + ;
Q.push(e.from);
}
}
}
return vis[s];
} void ClearAll(int n) { ///为了重新建边
this->n = n;
for(int i = ; i < n; i++) G[i].clear();
edges.clear();
} void ClearFlow() { ///清除流量
for(int i = ; i < edges.size(); i++) edges[i].flow = ;
} int Augment() { ///沿着增广边扩展flow
int x = t, a = INF;
while(x != s) {
Edge& e = edges[p[x]];
a = min(a, e.cap-e.flow);
x = edges[p[x]].from;
}
x = t;
while(x != s) {
edges[p[x]].flow += a;
edges[p[x]^].flow -= a;
x = edges[p[x]].from;
}
return a;
} int Maxflow(int s, int t) { ///求最大流
this->s = s; this->t = t;
int flow = ;
BFS();
memset(num, , sizeof(num));
for(int i = ; i < n; i++) num[d[i]]++;
int x = s;
memset(cur, , sizeof(cur));
while(d[s] < n) {
if(x == t) {
flow += Augment();
x = s;
}
int ok = ;
for(int i = cur[x]; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(e.cap > e.flow && d[x] == d[e.to] + ) { // Advance
ok = ;
p[e.to] = G[x][i];
cur[x] = i; // 注意
x = e.to;
break;
}
}
if(!ok) { /// Retreat 重新对待。因为该节点在目前的d下已经不存在增广路了,所以我们要对他进行增广
int m = n-; // 初值注意
for(int i = ; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(e.cap > e.flow) m = min(m, d[e.to]);
}
if(--num[d[x]] == ) break;
num[d[x] = m+]++;
cur[x] = ; // 注意
if(x != s) x = edges[p[x]].from;
}
}
return flow;
} vector<int> Mincut() { /// call this after maxflow求最小割,就是S和T中还存在流量的东西
BFS();///重新bfs一次
vector<int> ans;
for(int i = ; i < edges.size(); i++) {
Edge& e = edges[i];
if(!vis[e.from] && vis[e.to] && e.cap > ) {
ans.push_back(i);
}
}
return ans;
} void Reduce() {
for(int i = ; i < edges.size(); i++) edges[i].cap -= edges[i].flow;
} void print() {
printf("Graph:\n");
for(int i = ; i < edges.size(); i++)
printf("%d->%d, %d, %d\n", edges[i].from, edges[i].to , edges[i].cap, edges[i].flow);
}
};
ISAP g;
Dinic模板
lrj的代码告诉我,不能随便的在Edge里面增加一个cost,因为这样在跑起来的时候会慢100ms(在UVA上就慢了100ms,更何况其他的)
const int INF = 0x3f3f3f3f;
struct Edge {
int from, to, cap, flow;
}; struct Dinic {
int n, m, s, t; ///节点的个数,边的编号,起点,终点
vector<Edge> edges; // 边数的两倍
vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[maxn]; // BFS使用
int d[maxn]; // 从起点到i的距离
int cur[maxn]; // 当前弧指针
/////////蓝书363
int inq[maxn]; // 是否在队列中
int p[maxn]; // 上一条弧
int a[maxn]; //可改进量 void ClearAll(int n) {
this->n = n; ///这个赋值千万不能忘
for(int i = ; i < n; i++) G[i].clear();
edges.clear();
} void ClearFlow() { ///清除流量,例如蓝书368的UVA11248里面的优化,就有通过清除流量来减少增广次数的
for(int i = ; i < edges.size(); i++) edges[i].flow = ;
} void Reduce() {///直接减少cap,也是减少增广次数的
for(int i = ; i < edges.size(); i++) edges[i].cap -= edges[i].flow;
} void AddEdge(int from, int to, int cap) {
edges.push_back((Edge){from, to, cap, });
edges.push_back((Edge){to, from, , });
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS() {///bfs构建层次图
memset(vis, , sizeof(vis));
queue<int> Q;
Q.push(s);
vis[s] = ;
d[s] = ;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for(int i = ; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow) {//只考虑残量网络中的弧
vis[e.to] = ;
d[e.to] = d[x] + ;
Q.push(e.to);
}
}
}
return vis[t];
} int DFS(int x, int a) {///a表示目前为止,所有弧的最小残量。但是也可以用它来限制最大流量,例如蓝书368LA2957,利用a来保证增量,使得最后maxflow=k
if(x == t || a == ) return a;
int flow = , f;
for(int& i = cur[x]; i < G[x].size(); i++) {//从上次考虑的弧,即已经访问过的就不需要在访问了
Edge& e = edges[G[x][i]];
if(d[x] + == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > ) {
e.flow += f;
edges[G[x][i]^].flow -= f;
flow += f;
a -= f;
if(a == ) break;//如果不在这里终止,效率会大打折扣
}
}
return flow;
}
/**最大流*/
int Maxflow(int s, int t) {
this->s = s; this->t = t;
int flow = ;
while(BFS()) {
memset(cur, , sizeof(cur));
flow += DFS(s, INF);///这里的INF可以发生改变,因为INF保证的是最大残量。但是也可以通过控制残量来控制最大流
}
return flow;
} /**指定流量的最大流*/
/*这里的limit表示离上限还有多少距离
int Maxflow(int s, int t, int limit) {
this->s = s; this->t = t;
int flow = 0;
while(BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, limit - flow);///这里的INF可以发生改变,因为INF保证的是最大残量。但是也可以通过控制残量来控制最大流
if(flow == limit) break;
}
return flow;
}
*/
/**最小割*/
vector<int> Mincut() { /// call this after maxflow求最小割,就是S和T中还存在流量的东西
BFS();///重新bfs一次
vector<int> ans;
for(int i = ; i < edges.size(); i++) {
Edge& e = edges[i];
if(vis[e.from] && !vis[e.to] && e.cap > ) {///这里和ISAP不一样
ans.push_back(i);
}
}
return ans;
} void debug(){///debug
for (int i = ; i < edges.size(); i++){
printf("u = %d v = %d cap = %d flow = %d\n", edges[i].from + , edges[i].to + , edges[i].cap, edges[i].flow);
}
}
};
Dinic g;
Dinit+最小费用流模板(暂时,功能和注释需要不断加强,然后慢慢变得逐渐完整了,既可以求最大流,也可以求最小费用)
const int INF = 0x3f3f3f3f;
struct Edge {
int from, to, cap, flow, cost;
Edge(int f = , int t = , int c = , int fo = , int cost = ): from(f), to(t), cap(c), flow(fo), cost(cost){}
}; struct Dinic {
int n, m, s, t; ///节点的个数,边的编号,起点,终点
vector<Edge> edges; // 边数的两倍
vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[maxn]; // BFS使用
int d[maxn]; // 从起点到i的距离
int cur[maxn]; // 当前弧指针
/////////蓝书363
int inq[maxn]; // 是否在队列中
int p[maxn]; // 上一条弧
int a[maxn]; //可改进量 void ClearAll(int n) {
this->n = n; ///这个赋值千万不能忘
for(int i = ; i < n; i++) G[i].clear();
edges.clear();
} void ClearFlow() { ///清除流量,例如蓝书368的UVA11248里面的优化,就有通过清除流量来减少增广次数的
for(int i = ; i < edges.size(); i++) edges[i].flow = ;
} void Reduce() {///直接减少cap,也是减少增广次数的
for(int i = ; i < edges.size(); i++) edges[i].cap -= edges[i].flow;
} void AddEdge(int from, int to, int cap, int cost = ) {
edges.push_back((Edge){from, to, cap, , cost});
edges.push_back((Edge){to, from, , , -cost});
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS() {///bfs构建层次图
memset(vis, , sizeof(vis));
queue<int> Q;
Q.push(s);
vis[s] = ;
d[s] = ;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for(int i = ; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow) {//只考虑残量网络中的弧
vis[e.to] = ;
d[e.to] = d[x] + ;
Q.push(e.to);
}
}
}
return vis[t];
} int DFS(int x, int a) {///a表示目前为止,所有弧的最小残量。但是也可以用它来限制最大流量,例如蓝书368LA2957,利用a来保证增量,使得最后maxflow=k
if(x == t || a == ) return a;
int flow = , f;
for(int& i = cur[x]; i < G[x].size(); i++) {//从上次考虑的弧,即已经访问过的就不需要在访问了
Edge& e = edges[G[x][i]];
if(d[x] + == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > ) {
e.flow += f;
edges[G[x][i]^].flow -= f;
flow += f;
a -= f;
if(a == ) break;//如果不在这里终止,效率会大打折扣
}
}
return flow;
}
/**最大流*/
int Maxflow(int s, int t) {
this->s = s; this->t = t;
int flow = ;
while(BFS()) {
memset(cur, , sizeof(cur));
flow += DFS(s, INF);///这里的INF可以发生改变,因为INF保证的是最大残量。但是也可以通过控制残量来控制最大流
}
return flow;
} /**指定流量的最大流*/
/*这里的limit表示离上限还有多少距离
int Maxflow(int s, int t, int limit) {
this->s = s; this->t = t;
int flow = 0;
while(BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, limit - flow);///这里的INF可以发生改变,因为INF保证的是最大残量。但是也可以通过控制残量来控制最大流
if(flow == limit) break;
}
return flow;
}
*/
/**最小割*/
vector<int> Mincut() { /// call this after maxflow求最小割,就是S和T中还存在流量的东西
BFS();///重新bfs一次
vector<int> ans;
for(int i = ; i < edges.size(); i++) {
Edge& e = edges[i];
if(vis[e.from] && !vis[e.to] && e.cap > ) {///这里和ISAP不一样
ans.push_back(i);
}
}
return ans;
}
/***************////以下是最小费用流算法
bool BellmanFord(int s, int t, int &flow, int &cost) {///当然,cost是LL,也要记得修改
this->s = s; this->t = t;
for(int i = ; i < n; i++) d[i] = INF;
memset(inq, , sizeof(inq));
d[s] = ; inq[s] = ; p[s] = ; a[s] = INF; queue<int> Q;
Q.push(s);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = ;
for(int i = ; 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] = ; }
}
}
} if(d[t] == INF) return false;///这里的条件看情况的
flow += a[t];
cost += d[t] * a[t];
int u = t;
while(u != s) {
edges[p[u]].flow += a[t];
edges[p[u]^].flow -= a[t];
u = edges[p[u]].from;
}
return true;
} /// 需要保证初始网络中没有负权圈(属于调用最小费用流算法)
int Mincost(int s, int t) {
int flow = , cost = ;
while(BellmanFord(s, t, flow, cost)); ///这里的flow是看情况的
return cost;
} void debug(){///debug
for (int i = ; i < edges.size(); i++){
printf("u = %d v = %d cap = %d flow = %d\n", edges[i].from + , edges[i].to + , edges[i].cap, edges[i].flow);
}
}
};
Dinic g;
ISAP + 最小费用流
const int INF = 0x3f3f3f3f;
struct Edge {
int from, to, cap, flow, cost;
Edge(int f = , int t = , int c = , int fo = , int cost = ): from(f), to(t), cap(c), flow(fo), cost(cost){}
}; struct ISAP {
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[maxn]; // BFS使用
int d[maxn]; // 从起点到i的距离
int cur[maxn]; // 当前弧指针
int p[maxn]; // 可增广路上的上一条弧
int num[maxn]; // 距离标号计数
/////////蓝书363
int inq[maxn]; // 是否在队列中
int a[maxn]; //可改进量 void AddEdge(int from, int to, int cap, int cost = ) {
edges.push_back((Edge){from, to, cap, , cost});
edges.push_back((Edge){to, from, , , -cost});
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS() {
memset(vis, , sizeof(vis));
queue<int> Q;
Q.push(t);
vis[t] = ;
d[t] = ;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for(int i = ; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]^];///因为t本来就是最后一个结点,一般最后都是反向边的?
if(!vis[e.from] && e.cap > e.flow) {
vis[e.from] = ;
d[e.from] = d[x] + ;
Q.push(e.from);
}
}
}
return vis[s];
} void ClearAll(int n) { ///为了重新建边
this->n = n;
for(int i = ; i < n; i++) G[i].clear();
edges.clear();
} void ClearFlow() { ///清除流量
for(int i = ; i < edges.size(); i++) edges[i].flow = ;
} int Augment() { ///沿着增广边扩展flow
int x = t, a = INF;
while(x != s) {
Edge& e = edges[p[x]];
a = min(a, e.cap-e.flow);
x = edges[p[x]].from;
}
x = t;
while(x != s) {
edges[p[x]].flow += a;
edges[p[x]^].flow -= a;
x = edges[p[x]].from;
}
return a;
} int Maxflow(int s, int t) { ///求最大流
this->s = s; this->t = t;
int flow = ;
BFS();
memset(num, , sizeof(num));
for(int i = ; i < n; i++) num[d[i]]++;
int x = s;
memset(cur, , sizeof(cur));
while(d[s] < n) {
if(x == t) {
flow += Augment();
x = s;
}
int ok = ;
for(int i = cur[x]; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(e.cap > e.flow && d[x] == d[e.to] + ) { // Advance
ok = ;
p[e.to] = G[x][i];
cur[x] = i; // 注意
x = e.to;
break;
}
}
if(!ok) { /// Retreat 重新对待。因为该节点在目前的d下已经不存在增广路了,所以我们要对他进行增广
int m = n-; // 初值注意
for(int i = ; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(e.cap > e.flow) m = min(m, d[e.to]);
}
if(--num[d[x]] == ) break;
num[d[x] = m+]++;
cur[x] = ; // 注意
if(x != s) x = edges[p[x]].from;
}
}
return flow;
} vector<int> Mincut() { /// call this after maxflow求最小割,就是S和T中还存在流量的东西
BFS();///重新bfs一次
vector<int> ans;
for(int i = ; i < edges.size(); i++) {
Edge& e = edges[i];
if(!vis[e.from] && vis[e.to] && e.cap > ) {
ans.push_back(i);
}
}
return ans;
} void Reduce() {
for(int i = ; i < edges.size(); i++) edges[i].cap -= edges[i].flow;
} /***************////以下是最小费用流算法
bool BellmanFord(int s, int t, int &flow, int &cost) {///当然,cost是LL,也要记得修改
for(int i = ; i < n; i++) d[i] = INF;
memset(inq, , sizeof(inq));
d[s] = ; inq[s] = ; p[s] = ; a[s] = INF; queue<int> Q;
Q.push(s);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = ;
for(int i = ; 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] = ; }
}
}
} if(d[t] == INF) return false;///这里的条件看情况的
flow += a[t];
cost += d[t] * a[t];
int u = t;
while(u != s) {
edges[p[u]].flow += a[t];
edges[p[u]^].flow -= a[t];
u = edges[p[u]].from;
}
return true;
} /// 需要保证初始网络中没有负权圈(属于调用最小费用流算法)
int Mincost(int s, int t) {
int flow = , cost = ;
while(BellmanFord(s, t, flow, cost)); ///这里的flow是看情况的
return cost;
} void print() {
printf("Graph:\n");
for(int i = ; i < edges.size(); i++)
printf("%d->%d, %d, %d\n", edges[i].from, edges[i].to , edges[i].cap, edges[i].flow);
}
};
ISAP g;
//**********************************************************************************************************************************************************//
接下来开始探寻用head、next的建图方式了(垃圾POJ,毁我模板TAT,T我一脸)
最大流算法 ISAP 模板 和 Dinic模板的更多相关文章
- 最大流算法-ISAP
引入 最大流算法分为两类,一种是增广路算法,一种是预留推进算法.增广路算法包括时间复杂度\(O(nm^2)\)的EK算法,上界为\(O(n^2m)\)的Dinic算法,以及一些其他的算法.EK算法直接 ...
- 最大流当前弧优化Dinic模板
最大流模板: 普通最大流 无向图限制:将无向图的边拆成2条方向相反的边 无源汇点有最小流限制的最大流:理解为水管流量形成循环,每根水管有流量限制,并且流入量等于流出量 有源汇点的最小流限制的最大流 顶 ...
- 【最大流之EdmondsKarp算法】【HDU1532】模板题
题意:裸的最大流,什么是最大流,参考别的博客 运用复杂度最高的EK算法 O(M*N),模板来自紫书 #include <cstdio> #include <cstdlib> # ...
- 洛谷P3376【模板】网络最大流 Dinic模板
之前的Dinic模板照着刘汝佳写的vector然后十分鬼畜跑得奇慢无比,虽然别人这样写也没慢多少但是自己的就是令人捉急. 改成邻接表之后快了三倍,虽然还是比较慢但是自己比较满意了.虽然一开始ecnt从 ...
- hdu 1532 Dinic模板(小白书)
hdu1532 输入n,m. n条边,m个点,之后给出a到b的容量,求1到m的最大流. 注意:Dinic只能调用一次,因为原理是改变cap的值,如果调用多次一样的,那么第一次会对,其余的都会是0,因为 ...
- POJ 1273 Drainage Ditches (网络流Dinic模板)
Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover ...
- hiho一下 第115周:网络流一•Ford-Fulkerson算法 (Edmond-Karp,Dinic,SAP)
来看一道最大流模板水题,借这道题来学习一下最大流的几个算法. 分别用Edmond-Karp,Dinic ,SAP来实现最大流算法. 从运行结过来看明显SAP+当前弧优化+gap优化速度最快. hi ...
- (转)DEDECMS模板原理、模板标签学习 - .Little Hann
本文,小瀚想和大家一起来学习一下DEDECMS中目前所使用的模板技术的原理: 什么是编译式模板.解释式模板,它们的区别是什么? 模板标签有哪些种类,它们的区别是什么,都应用在哪些场景? 学习模板的机制 ...
- C++ Primer 学习笔记_75_模板与泛型编程 --模板定义
模板与泛型编程 --模板定义 引言: 所谓泛型程序就是以独立于不论什么特定类型的方式编写代码.使用泛型程序时,我们须要提供详细程序实例所操作的类型或值. 模板是泛型编程的基础.使用模板时能够无须了解模 ...
随机推荐
- “Code First Migrations ”工具【转】
在本篇文章中,我们学习如何使用实体框架的“Code First Migrations ”(也称为代码先行功能)工具,使用其中的“迁移”功能对模型类进行一些修改,同时同步更新对应数据库的表结构. 默认情 ...
- Python的异常
一.异常的常用形式 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行.一般情况下,在Python无法正常处理程序时就会发生一个异常.异常是Python对象,表示一个错误.当Pyth ...
- Mysql 启动运行
MYSQL默认端口:3306用户: root 也可自己添加用户启动数据库服务名: MYSQL (在安装的时候会设置) 在开始菜单栏->附件->右键命令提示符->以管理员身份运行: ...
- 一些可能有点用处的C#开发经验
前言: 下个月就要去进行Java开发了,以后C#碰的就少了(可惜去年买了三本C#的书,几乎还是全新的……),平时一些经验都记在OneNote里面,现在收集整理出来,因为只能利用交接工作的打酱油的时间, ...
- json 处理日期格式
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") private Date createT ...
- 算法搬运之BFPRT算法
原文连接:http://noalgo.info/466.html BFPRT算法,又称为中位数的中位数算法,由5位大牛(Blum . Floyd . Pratt . Rivest . Tarjan)提 ...
- Spring实战第五章学习笔记————构建Spring Web应用程序
Spring实战第五章学习笔记----构建Spring Web应用程序 Spring MVC基于模型-视图-控制器(Model-View-Controller)模式实现,它能够构建像Spring框架那 ...
- 企业级Tomcat部署配置
1.1 Tomcat简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Sun和其他一些公司及个人 ...
- 论文翻译_Tracking The Untrackable_Learning To Track Multiple Cues with Long-Term Dependencies_IEEE2017
Tracking The Untrackable: Learning to Track Multiple Cues with Long-Term Dependencies 跟踪不可跟踪:学习跟踪具有长 ...
- linux备忘录-日志档案
linux的日志档案 linux的日志档案记录系统或程序在运行过程中产生的一些信息,例如事件的记录,错误的记录等等.特别是在发生错误时,我们可以通过日志档案找到错误发生的根源,例如当我们无法启动邮件服 ...