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模板的更多相关文章

  1. 最大流算法-ISAP

    引入 最大流算法分为两类,一种是增广路算法,一种是预留推进算法.增广路算法包括时间复杂度\(O(nm^2)\)的EK算法,上界为\(O(n^2m)\)的Dinic算法,以及一些其他的算法.EK算法直接 ...

  2. 最大流当前弧优化Dinic模板

    最大流模板: 普通最大流 无向图限制:将无向图的边拆成2条方向相反的边 无源汇点有最小流限制的最大流:理解为水管流量形成循环,每根水管有流量限制,并且流入量等于流出量 有源汇点的最小流限制的最大流 顶 ...

  3. 【最大流之EdmondsKarp算法】【HDU1532】模板题

    题意:裸的最大流,什么是最大流,参考别的博客 运用复杂度最高的EK算法 O(M*N),模板来自紫书 #include <cstdio> #include <cstdlib> # ...

  4. 洛谷P3376【模板】网络最大流  Dinic模板

    之前的Dinic模板照着刘汝佳写的vector然后十分鬼畜跑得奇慢无比,虽然别人这样写也没慢多少但是自己的就是令人捉急. 改成邻接表之后快了三倍,虽然还是比较慢但是自己比较满意了.虽然一开始ecnt从 ...

  5. hdu 1532 Dinic模板(小白书)

    hdu1532 输入n,m. n条边,m个点,之后给出a到b的容量,求1到m的最大流. 注意:Dinic只能调用一次,因为原理是改变cap的值,如果调用多次一样的,那么第一次会对,其余的都会是0,因为 ...

  6. POJ 1273 Drainage Ditches (网络流Dinic模板)

    Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover ...

  7. hiho一下 第115周:网络流一•Ford-Fulkerson算法 (Edmond-Karp,Dinic,SAP)

    来看一道最大流模板水题,借这道题来学习一下最大流的几个算法. 分别用Edmond-Karp,Dinic ,SAP来实现最大流算法. 从运行结过来看明显SAP+当前弧优化+gap优化速度最快.   hi ...

  8. (转)DEDECMS模板原理、模板标签学习 - .Little Hann

    本文,小瀚想和大家一起来学习一下DEDECMS中目前所使用的模板技术的原理: 什么是编译式模板.解释式模板,它们的区别是什么? 模板标签有哪些种类,它们的区别是什么,都应用在哪些场景? 学习模板的机制 ...

  9. C++ Primer 学习笔记_75_模板与泛型编程 --模板定义

    模板与泛型编程 --模板定义 引言: 所谓泛型程序就是以独立于不论什么特定类型的方式编写代码.使用泛型程序时,我们须要提供详细程序实例所操作的类型或值. 模板是泛型编程的基础.使用模板时能够无须了解模 ...

随机推荐

  1. P1855 榨取kkksc03

    P1855 榨取kkksc03 题目描述 以下皆为真实的故事. 洛谷2的团队功能是其他任何oj和工具难以达到的.借助洛谷强大的服务器资源,任何学校都可以在洛谷上零成本的搭建oj并高效率的完成训练计划. ...

  2. Sqlite Datetime类型详解

    日期和时间函数 date(timestring, modifier, modifier, ...) time(timestring, modifier, modifier, ...) datetime ...

  3. VS2010使用NuGet程序包管理器

    使用C#过程中经常需要使用一些扩展包,例如sqlite,json解析等. VS2010自带了一个扩展管理器,里面可以下载到AStyle,Visual Assit等有用的插件. VS2010中点击[工具 ...

  4. Qt 汽车仪表 QWidget

    今天是2016年的最后一个工作日,在这个最后工作日里面,和以为网友要了一点练手的素材文件,经过网友确认,不涉及商业机密,在这里分享一下,如侵权,请联系我删除. 先上程序运行图 这里显示数字,闪烁等都没 ...

  5. (原)自定义资源预览工具:DZAssetPreviewPlugin(1)

    @author: 白袍小道 转载请说明,谢谢     题记 后续工具制作单独作为一本(小道用的是OneNote,这样发布简单点.*--*) 总计放到写完后.     目的 1.快速预览资源(因为大部分 ...

  6. 剑指offer-旋转数组的最小数字06

    题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋 ...

  7. java多线程二之线程同步的三种方法

          java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Se ...

  8. ios UI自动化测试学习笔记

    一.一些注意事项: 1.做自动化测试时注意如果是真机话首先要设置不锁屏. 2.自动化测试过程中如果程序后台或崩溃了.脚本运行将会暂停,直到程序再次回到前台. 3.必须明确指定关闭自动测试,测试完成或中 ...

  9. OO5-7次作业总结

    写在最前面: 转眼间就又到了一月一次的总结时间,这次的三个作业,我个人感觉可能是最令人难受的三次作业了.不只是因为它们是多线程,更是因为它们几乎是全新的三次作业,每次的代码几乎都要重头开始. 第五次作 ...

  10. Apache服务器的Options 的 Indexes FollowSymLinks详解

    禁止显示Apache目录列表 - Indexes FollowSymLinks 如何修改目录的配置以禁止显示 Apache 目录列表. 缺省情况下如果你在浏览器输入地址: http://localho ...