P3376 【模板】网络最大流( Edmonds-krap、Dinic、ISAP 算法)
P3376 【模板】网络最大流( Edmonds-krap、Dinic、ISAP 算法)
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。
输入格式 第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含三个正整数ui、vi、wi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi)
输出格式 一行,包含一个正整数,即为该网络的最大流。
输入输出样例
输入 #1 复制
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40
输出 #1 复制
50
说明/提示
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=10,M<=25
对于70%的数据:N<=200,M<=1000
对于100%的数据:N<=10000,M<=100000
样例说明:
题目中存在3条路径:
4–>2–>3,该路线可通过20的流量
4–>3,可通过20的流量
4–>2–>1–>3,可通过10的流量(边4–>2之前已经耗费了20的流量)
故流量总计20+20+10=50。输出50。
思路
最大流板子。。。。
大佬博客传送门1
传送门2
传送门3
传说门4
题解一(Edmonds-krap)
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;#define INF 0x3f3f3f3f
const int maxn = 10005;
const int maxm = 300005;
int n,m,s,e;struct Edge
{int u,v,next;int cap,flow;
} edge[2*maxm];
int head[2*maxm];int k = -1;
void Add(int u, int v, int w)
{edge[++ k] = (Edge){ u, v, head[u], w, 0};head[u] = k;edge[++ k] = (Edge){ v, u, head[v], 0, 0};head[v] = k;
}
int flag = 0; //flag == 0 表示还能找到增广路int bfs(int s, int e)
{int min_flow[maxn]; //min_flow[i] 表示到达第 i 号节点时,之前所有的路径中 最小的 边的流量cap - 已经流过的流量flowint pre[maxm]; //记录增光路时,当前节点是由那个那条边找到的,这样在找到增光路之后,我们可以根据 pre[] 数组回推其他 组成该增光路的边memset(min_flow, 0, sizeof(min_flow)); //min_flow[i] == 0 表示之前没有走过 i 节点min_flow[s] = INF;pre[s] = -1;queue<int> q;q.push(s);int u,v,flow;while(! q.empty()){u = q.front(); q.pop();for(int i = head[u]; i != -1; i = edge[i].next){v = edge[i].v;flow = edge[i].cap - edge[i].flow;if(flow > 0 && ! min_flow[v]) //所走的这条边还有 剩余的空间cap,并且该节点还没有被走过。。{pre[v] = i;min_flow[v] = min(min_flow[u], flow);q.push(v);}}if(min_flow[e])break;}if(! min_flow[e]) //一只到更新结束,终点到最小增加值还是等于0,那么说从起点到终点已经没有增广路了flag = 1;//这一点千万不要忘,,,,把用过的水流在这条增光路上都减去。。。。for(int j = e; pre[j] != -1; j = edge[pre[j]].u){edge[pre[j]].flow += min_flow[e];edge[pre[e]^1].flow -= min_flow[e];}return min_flow[e]; //返回最小增加值到 答案中
}int max_flow()
{int mx_flw = 0;while(1){mx_flw += bfs(s, e);if(flag)break;}return mx_flw;
}void init()
{memset(head, -1, sizeof(head));k = -1;
}int main()
{ios::sync_with_stdio(false); cin.tie(nullptr);//freopen("T.txt","r",stdin);cin >> n >> m >> s >> e;init();int u,v,w;for(int i = 1; i <= m; i ++){cin >> u >> v >> w;Add(u, v, w);}cout << max_flow() << endl;return 0;
}
题解二(Dinic)
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;#define INF 1e9
#define ll long long
const int maxn = 100005;
const int maxm = 150000;
int n,m;struct Edge
{int v;ll w;int next;
} edge[maxm];
int head[maxn], cur[maxn];
int deep[maxn];int k;
void Add(int u, int v, ll w)
{edge[++ k] = (Edge){ v, w, head[u]};head[u] = k;edge[++ k] = (Edge){ u, 0, head[v]};head[v] = k;
}
//bfs 为图分层bool bfs(int s, int e)
{memset(deep, 0x7f, sizeof(deep));for(int i = 1; i <= n; i ++) cur[i] = head[i];deep[s] = 0;queue<int> q;q.push(s);int u,v;ll w;while(! q.empty()){u = q.front(); q.pop();for(int i = head[u]; i != -1; i = edge[i].next){v = edge[i].v;w = edge[i].w;if(w && deep[v] > INF){deep[v] = deep[u] + 1;q.push(v);}}}if(deep[e] >= INF)return false;return true;
}//dfs 一次找多条增光路(相当于找了一个增广网。。)
ll dfs(int now, int e, ll limit)
{if(! limit || now == e) return limit;ll flow = 0, f;for(int i = cur[now]; i != -1; i = edge[i].next){cur[now] = i; //千万注意这一步的意思啊。。这一步是因为 dfs的特性是每次增广一定是增广,那么下一次就不必再检查它了,而直接看第一个未被检查的边if(deep[edge[i].v] == deep[now] + 1 && (f = dfs(edge[i].v, e, min(limit, edge[i].w)))){flow += f;limit -= f;edge[i].w -= f;edge[i^1].w += f;if(! limit)break;}}return flow;
}ll Dinic(int s, int e)
{ll mx_flw = 0;while(bfs(s, e))mx_flw += dfs(s, e, INF);return mx_flw;
}void init()
{k = -1;memset(head, -1, sizeof(head));
}int main()
{ios::sync_with_stdio(false); cin.tie(0);//freopen("T.txt","r",stdin);int s,e;cin >> n >> m >> s >> e;init();int u,v;ll w;for(int i = 1; i <= m; i ++)cin >> u >> v >> w, Add(u, v, w);cout << Dinic(s, e);return 0;
}
题解三(ISAP)
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;#define INF 1e9
const int maxn = 10005;
const int maxm = 200005;
int n, m, s, e;
int k;struct Edge
{int v,w,next;
} edge[2 * maxm];int head[maxn],cur[maxn],deep[maxn];
int last[maxm];
int num[maxm]; // num 桶,用来统计每个分层的节点的数量void Add(int u, int v, int w)
{edge[++ k] = (Edge){ v, w, head[u]};head[u] = k;edge[++ k] = (Edge){ u, 0, head[v]};head[v] = k;
}//bfs 用于更新deep层
void bfs(int e)
{// for(int i = 0; i <= n; i ++)
// cur[i] = head[i], deep[i] = n;for(int i = 0; i <= m; i ++) cur[i] = head[i];for(int i = 1; i <= n; i ++) deep[i] = n;deep[e] = 0;queue<int> q;q.push(e);int u, v, w;while(! q.empty()){u = q.front(); q.pop();for(int i = head[u]; i != -1; i = edge[i].next){v = edge[i].v;if(edge[i^1].w && deep[v] == n) //正图 边存在 且 v这个节点没有被求过{deep[v] = deep[u] + 1;q.push(v);}}}
}int Add_flow(int s, int e)
{int ans = INF;int now = e;while(now != s){ans = min(ans, edge[last[now]].w);now = edge[last[now]^1].v;}now = e;while(now != s){edge[last[now]].w -= ans;edge[last[now]^1].w += ans;now = edge[last[now]^1].v;}return ans;
}int isap(int s, int e)
{int now = s; //从起点开始进行操作bfs(e); //先找出来一条边 被操作的增光路for(int i = 1; i <= n; i ++) num[deep[i]] ++;int mx_flw = 0;while(deep[s] < n){if(now == e) //如果到达汇点直接增广,重新回到源点进行下一轮增广{mx_flw += Add_flow(s, e);now = s;}bool has_find = 0;for(int i = cur[now]; i != -1; i = edge[i].next){if(edge[i].w && deep[now] == deep[edge[i].v] + 1){has_find = 1; //做标记已经找到一种可行路径cur[now] = i; //优化当前弧now = edge[i].v;last[edge[i].v] = i;break;}}if(! has_find){int minn = n - 1;for(int i = head[now]; i != -1; i = edge[i].next)if(edge[i].w)minn = min(minn, deep[edge[i].v]);if( (-- num[deep[now]]) == 0) break; //gap 优化出现了断层num[deep[now] = minn + 1] ++;cur[now] = head[now];if(now != s)now = edge[last[now]^1].v;}}return mx_flw;
}void init()
{k = -1;memset(head, -1, sizeof(head));
}int main()
{ios::sync_with_stdio(false); cin.tie(0);//freopen("T.txt","r",stdin);cin >> n >> m >> s >> e;init();int u,v,w;for(int i = 1; i <= m; i ++)cin >> u >> v >> w, Add(u, v, w);cout << isap(s, e);return 0;
}
P3376 【模板】网络最大流( Edmonds-krap、Dinic、ISAP 算法)相关推荐
- 【ybt金牌导航3-2-1】【luogu P3376】网络最大流【Dinic算法】
网 络 最 大 流 网络最大流 网络最大流 题目链接:ybt金牌导航3-2-1 / luogu P3376 题目 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入 第一行包含四个正整数 ...
- [Luogu] P3376 模板-网络流-最大流
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- 【洛谷P3376】网络最大流【网络流】
分析 网络流算法本身是之前学过的,今天拿出来复习打个板子. 最原始的思路应该是搜索每一条路,每次进行增广的操作,知道不能增广为止.显然,这种思路复杂度比较高. 如何进行优化?就是dinic算法.上面那 ...
- 网络最大流的三种基础算法
#include<iostream> #include<cstring> #include<queue> #include<cstdio> #inclu ...
- 网络流之最大流 EK/Dinic/Isap算法 学习笔记
EK 算法流程 不停地找增广路进行增广,知道找不到增广路为止. 每一次bfs只找一条增广路. 时间复杂度O(VE2)O(VE^2) 代码 // codevs 1993 #include<iost ...
- 最大流ISAP算法模板
这两天学习了最大流,下面是ISAP算法模板: const int inf = 0x3fffffff; template <int N, int M> struct Isap {int to ...
- Dinic最大流 || Luogu P3376 【模板】网络最大流
题面:[模板]网络最大流 代码: 1 #include<cstring> 2 #include<cstdio> 3 #include<iostream> 4 #de ...
- 【网络流】解题报告:luogu P3376 【模板】网络最大流
题目链接: P3376 [模板]网络最大流 Dinic Dinic算法是网络流最大流的优化算法之一,每一步对原图进行分层,然后用DFS求增广路.时间复杂度是O(n^2*m),Dinic算法最多被分为n ...
- 洛谷P3376 【模板】网络最大流
P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...
- 【洛谷 - P3376 】【模板】网络最大流
题干: 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行包 ...
最新文章
- List,Set,Collection,Collections比较
- 三: cocos2d-x代码分析
- 新书发布《每天5分钟玩转Docker容器技术》
- 初试Windows 8 RTM
- Vue + Element UI——侧边栏LOGO设计DEMO
- 为什么网页背景图片都切开
- 服务器日志记录_5种改善服务器日志记录的技术
- Google Maps Android API v2 (2)- 地图对象
- SPFA - Luogu 3385 【模板】负环
- 精简版oracle客户端程序
- Linux:什么是 i386、i586、 i686、noarch?
- 复联4定档 4.24——十一年21部漫威电影,用数据为你梳理口碑、票房、主演最佳......
- 激情巴布部落畅快一日游
- Python入门(10)——宝可梦数据集探索
- 响应式编程之一:概述
- sublimelinter php 语法不起作用,sublime安装插件sublimeLinter不起作用解决办法
- MDF和DHF、DMR、DHR三者差异?注册与备案文件?
- Vue中的深坑——component和components
- 时间的过客怎么用计算机完整版,抖音时间的过客MC名决在哪看?附歌词完整版原文...
- 《数字集成电路物理设计——陈春章》学习笔记
热门文章
- 小程序自动定位当前位置
- Web 开发权威指南
- Word文档标题编号调整
- 传递组播与广播帧:数据待传指示传递信息(DTIM)
- 台式计算机时间不能同步,电脑时间同步不了怎么办
- 江苏自考计算机专业,2021年江苏自考本科专业选择:计算机类专业前景如何?有哪些科目?...
- 有关古希腊罗马神话与医学术语的联系的英文文献去哪找?
- 苹果x人脸识别突然失灵_iPhone手机触摸屏失灵怎么办?成都苹果维修点教你轻松解决...
- 《云计算技术与应用基础》课程标准
- 家庭网络拓扑结构示意图