P3376 【模板】网络最大流
2017-04-23 08:47
411 查看
首先感谢(http://blog.csdn.net/x_y_q_/article/details/51999466)核心思路
http://blog.csdn.net/x_y_q_/article/details/51999466
一、首先是FF算法,dfs找增广路,
奉上最简模板(邻接矩阵)
[b]当然需要改为vector或者数组模拟临接链表
下面是vector
数组莫以邻接链表,cost[i]-=d,cost[i^1]+=d;
然而基于dfs的缺点,还是不够快,所以下面EK算法登场
二、EK算法,用bfs来找增广路
也可以用数组模拟临接链表
三、第三种Dinic(以上两种的结合)
Dinic算法的基本思路:
层次图:分层图,以[从原点到某点的最短距离]分层的图,距离相等的为一层,(比如上图的分层为{1},{2,4},{3})
观察前面的dfs算法,对于层次相同的边,会经过多次重复运算,很浪费时间,那么,可以考虑先对原图分好层产生新的层次图,即保存了每个点的层次,注意,很多人会把这里的边的最大容量跟以前算最短路时的那个权值混淆,其实这里每个点之间的距离都可以看作单位距离,然后对新图进行dfs,这时的dfs就非常有层次感,有筛选感了,同层次的点不可能在同一跳路径中,直接排除。那么运行速度就会快很多了。
代码;
http://blog.csdn.net/x_y_q_/article/details/51999466
一、首先是FF算法,dfs找增广路,
奉上最简模板(邻接矩阵)
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #include<queue> #define INF 100000000 using namespace std; int map[10009][10009]; bool used[10009]; int n,m,s,t; int dfs(int b,int e,int f) { int d; if(b==e) return f; for(int i=1;i<=n;i++) { if(map[i]>0&&!used[i]) { used[i]=true; d=dfs(i,e,min(f,map[b][i])); if(d>0) { map[b][i]-=d; map[i][b]+=d; return d; } } } } int maxflow(int b,int e) { int flow=0; while(1) { memset(used,false,sizeof(used)); int d=dfs(b,e,INF); if(d==0) return flow;//没有增广路了 flow+=d; } return flow; } int main() { scanf("%d%d%d%d",&n,&m,&s,&t); for(int i=1;i<=m;i++) { int v,u,w; scanf("%d%d%d",&u,&v,&w); map[u][v]=w; } printf("%d\n",maxflow(s,t)); return 0; }
[b]当然需要改为vector或者数组模拟临接链表
下面是vector
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #include<queue> #define INF 100000000 using namespace std; struct H{ int to,cap,rev; }; vector <H> map[10009]; int n,m,s, f9a1 t; bool used[10009]; void add(int f,int t,int c) { map[f].push_back((H){t,c,map[t].size()}); map[t].push_back((H){f,0,map[f].size()-1}); } int dfs(int s1,int t1,int f) { if(s1==t1) return f; for(int i=0;i<map[s1].size();i++) { int t2=map[s1][i].to,c2=map[s1][i].cap; if(c2>0&&!used[t2]) { used[t2]=true; int d=dfs(t2,t1,min(map[s1][i].cap,f)); if(d>0) { map[s1][i].cap-=d; map[t2][map[s1][i].rev].cap+=d; return d; } } } } int maxflow(int s1,int t1) { int flow=0; while(1) { memset(used,false,sizeof(used)); int d=dfs(s1,t1,INF); if(d==0) return flow; flow+=d; } } int main() { scanf("%d%d%d%d",&n,&m,&s,&t); for(int i=1;i<=m;i++) { int v,u,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } printf("%d\n",maxflow(s,t)); return 0; }
数组莫以邻接链表,cost[i]-=d,cost[i^1]+=d;
然而基于dfs的缺点,还是不够快,所以下面EK算法登场
二、EK算法,用bfs来找增广路
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #include<queue> #define INF 100000000 using namespace std; int n,m,s1,t1; int flow[10009];//标记从源点到当前节点实际还剩多少流量可用 struct P{ int f,id; }pre[10009];//记录前驱,同时也可以标记是否在队列中 struct H{ int to,cap,rev; }; vector <H> v[10009]; void add(int f,int t,int c) { v[f].push_back((H){t,c,v[t].size()}); v[t].push_back((H){f,0,v[f].size()-1}); } queue <int> que; int bfs(int s,int t) { while(!que.empty()) que.pop(); for(int i=1;i<=n;i++) pre[i].f=-1; pre[s].f=0; flow[s]=INF; que.push(s); while(!que.empty()) { int k=que.front(); que.pop(); if(k==t) break; for(int i=0;i<v[k].size();i++) { H &tmp=v[k][i]; if(tmp.to!=s&&tmp.cap>0&&pre[tmp.to].f==-1) { pre[tmp.to].f=k,pre[tmp.to].id=i;//此处应注意前驱的记录和使用方法 flow[tmp.to]=min(tmp.cap,flow[k]); que.push(tmp.to); } } } return pre[t].f==-1?-1:flow[t]; } int maxflow(int s,int t) { int mflow=0,d; while((d=bfs(s,t))!=-1) { mflow+=d; int k=t; while(k!=s) { int p=pre[k].f; v[p][pre[k].id].cap-=d; v[k][v[p][pre[k].id].rev].cap+=d;//利用反向边 k=p; } } return mflow; } int main() { scanf("%d%d%d%d",&n,&m,&s1,&t1); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } printf("%d\n",maxflow(s1,t1)); return 0; }
也可以用数组模拟临接链表
三、第三种Dinic(以上两种的结合)
Dinic算法的基本思路:
根据残量网络计算层次图。 在层次图中使用DFS进行增广直到不存在增广路 重复以上步骤直到无法增广
层次图:分层图,以[从原点到某点的最短距离]分层的图,距离相等的为一层,(比如上图的分层为{1},{2,4},{3})
观察前面的dfs算法,对于层次相同的边,会经过多次重复运算,很浪费时间,那么,可以考虑先对原图分好层产生新的层次图,即保存了每个点的层次,注意,很多人会把这里的边的最大容量跟以前算最短路时的那个权值混淆,其实这里每个点之间的距离都可以看作单位距离,然后对新图进行dfs,这时的dfs就非常有层次感,有筛选感了,同层次的点不可能在同一跳路径中,直接排除。那么运行速度就会快很多了。
代码;
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #include<queue> #define INF 100000000 using namespace std; int dep[10009],n,m,s1,t1; struct H{ int to,cap,rev; }; vector <H> v[10009]; void add(int f,int t,int c) { v[f].push_back((H){t,c,v[t].size()}); v[t].push_back((H){f,0,v[f].size()-1}); } int bfs(int s,int t) { memset(dep,-1,sizeof(dep)); queue <int> que; while(!que.empty()) que.pop(); que.push(s); dep[s]=0;//!!! while(!que.empty()) { int k=que.front(); que.pop(); for(int i=0;i<v[k].size();i++) { H &tmp=v[k][i]; if(dep[tmp.to]==-1&&tmp.cap>0) { dep[tmp.to]=dep[k]+1; que.push(tmp.to); } } } return dep[t]!=-1; } int dfs(int s,int t,int f) { int d; if(s==t) return f; for(int i=0;i<v[s].size();i++) { H &tmp=v[s][i]; if(tmp.cap>0&&dep[tmp.to]==dep[s]+1&&(d=dfs(tmp.to,t,min(f,tmp.cap)))) { v[s][i].cap-=d; v[tmp.to][tmp.rev].cap+=d; return d; } } return 0; } int dinic(int s,int t) { int flow=0; while(bfs(s,t)) { while(1) { int d=dfs(s,t,INF); if(d==0) break; flow+=d; } } return flow; } int main() { scanf("%d%d%d%d",&n,&m,&s1,&t1); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } printf("%d\n",dinic(s1,t1)); return 0; }
相关文章推荐
- Dinic算法 P3376 【模板】网络最大流
- 洛谷 P3376 【模板】网络最大流
- 洛谷 P3376【模板】网络最大流
- P3376 【模板】网络最大流
- P3376 【模板】网络最大流
- 洛谷 P3376 【模板】网络最大流
- P3376 【模板】网络最大流
- P3376 【模板】网络最大流(70)
- P3376 【模板】网络最大流dinic算法
- 网络最大流(SAP)模板
- 网络最大流增广路模板(EK & Dinic)
- 【模板】网络最大流
- [模板练习]网络最大流
- 【模板】网络最大流
- 算法模板——sap网络最大流 2(非递归+邻接表)
- 网络最大流最短增广路Dinic算法模板
- 网络最大流-ISAP算法详解与模板
- 【模板】ISAP网络最大流 (模板题:洛谷P3376)
- 最大网络流 模板
- 算法模板——sap网络最大流 3(递归+邻接表)