图论算法----网络流

模板:

最大流:

普通增广:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <queue>
 7 #define maxn 1010
 8 #define INF 0x3f3f3f3f
 9 using namespace std;
10 struct edge{
11     int to,cap,rev;
12 };
13 vector<edge>G[maxn];
14 bool used[maxn];
15 void addedge(int from,int to,int cap){
16     G[from].push_back((edge){to,cap,G[to].size()});
17     G[to].push_back((edge){from,0,G[from].size()-1});
18 }
19 int dfs(int v,int t,int f){
20     if (v==t)return f;
21     used[v]=true;
22     for (int i=0;i<G[v].size();++i){
23         edge &e = G[v][i];
24         if(!used[e.to]&&e.cap>0){
25             int d  = dfs(e.to,t,min(f,e.cap));
26             if (d>0){
27                 e.cap-=d;
28                 G[e.to][e.rev].cap +=d;
29                 return d;
30             }
31         }
32     }
33     return 0;
34 }
35 int max_flow(int s,int t){
36     int flow = 0;
37     while(1){
38         memset(used,0,sizeof(used));
39         int f = dfs(s,t,INF);
40         if(f==0)return flow;
41         flow+=f;
42     }
43 }
44 int main (){
45
46
47 }

Dinic:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<math.h>
 5 #include<iostream>
 6 #include<string>
 7 #include<algorithm>
 8 #include<vector>
 9 #include<queue>
10 #include<stack>
11 #include<map>
12 #define maxn 200001
13 #define INF 0x3f3f3f3f
14 using namespace std;
15 struct edge{
16     int to,cap,rev;
17 };
18 vector<edge>G[maxn];
19 void addedge(int from,int to,int cap){
20     G[from].push_back((edge){to,cap,G[to].size()});
21     G[to].push_back((edge){from,0,G[from].size()-1});
22 }
23 int level[maxn];//点的深度
24 int iter[maxn];//当前遍历到的边的下标
25 void bfs(int s){
26     memset(level,-1,sizeof(level));
27     queue<int>q;
28     level[s]=0;
29     q.push(s);
30     while(!q.empty()){
31         int v = q.front();
32         q.pop();
33         for (int i=0;i<G[v].size();++i){
34             edge &e = G[v][i];
35             if (e.cap>0&&level[e.to]<0){
36                 level[e.to]=level[v]+1;
37                 q.push(e.to);
38             }
39         }
40     }
41 }
42 int dfs(int v,int t,int f){
43     if (v==t)return f;
44     for (int &i =iter[v];i<G[v].size();++i){
45         edge &e = G[v][i];
46         if (e.cap>0&&level[v]<level[e.to]){
47             int d = dfs(e.to,t,min(f,e.cap));
48             if(d>0){
49                 e.cap-=d;
50                 G[e.to][e.rev].cap += d;
51                 return d;
52             }
53         }
54     }
55     return 0;
56 }
57 int max_flow(int s,int t){
58     int flow = 0;
59     while(1){
60         bfs(s);
61         if(level[t]<0)return flow;
62         memset(iter,0,sizeof(iter));
63         int f ;
64         while((f=dfs(s,t,INF))>0){
65             flow+=f;
66         }
67     }
68 }
69 int N,M;
70 int A[maxn],B[maxn];
71 int a[maxn],b[maxn],w[maxn];
72 void solve(){
73     int s = N,t= s+1;
74     for(int i=0;i<N;++i){
75         addedge(i,t,A[i]);
76         addedge(s,i,B[i]);
77     }
78     for(int i=0;i<M;++i){
79         addedge(a[i]-1,b[i]-1,w[i]);
80         addedge(b[i]-1,a[i]-1,w[i]);
81     }
82     int ans = max_flow(s,t);
83     printf("%d\n",ans);
84 }
85 int main (){
86     while(scanf("%d%d",&N,&M)!=EOF){
87         for(int i=0;i<N;++i)scanf("%d%d",&A[i],&B[i]);
88         for(int i=0;i<M;++i)scanf("%d%d%d",&a[i],&b[i],&w[i]);
89         solve();
90     }
91 }

SAP:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<string.h>
  4 #include<math.h>
  5 #include<iostream>
  6 #include<string>
  7 #include<algorithm>
  8 #include<vector>
  9 #include<queue>
 10 #include<stack>
 11 #include<map>
 12 #define maxn 200001
 13 #define maxm 1800000
 14 #define INF 0x3f3f3f3f
 15 using namespace std;
 16 const int inf=(1<<29);
 17 struct EDGE{
 18     int v,next;
 19     int cap;
 20 }ee[maxm];
 21 int head[maxn],gap[maxn]; //dep[maxn];
 22 int n,m,src,des,siz;//src=start,des=end;
 23 void init(){
 24     siz=0;
 25     memset(head,-1,sizeof head);
 26 }
 27 void addedge(int u,int v,int cap){
 28     ee[siz].v=v,ee[siz].cap=cap;
 29     ee[siz].next=head[u];
 30     head[u]=siz++;
 31
 32     ee[siz].v=u,ee[siz].cap=0;
 33     ee[siz].next=head[v];
 34     head[v]=siz++;
 35 }
 36 int dis[maxn],pre[maxn];
 37 int cur[maxn],aug[maxn];
 38
 39 int SAP(int s, int e, int n)
 40 {
 41     int max_flow = 0, v, u = s;
 42     int id, mindis;
 43     aug[s] = inf;
 44     pre[s] = -1;
 45     memset(dis, 0, sizeof(dis));
 46     memset(gap, 0, sizeof(gap));
 47     gap[0] = n;
 48     for (int i = 0; i <= n; ++i){//初始化当前弧为第一条弧
 49         cur[i] = head[i];
 50     }
 51
 52     while (dis[s] < n)
 53     {
 54         bool flag = false;
 55         if (u == e)
 56         {
 57             max_flow += aug[e];
 58             for (v = pre[e]; v != -1; v = pre[v])//路径回溯更新残留网络
 59             {
 60                 id = cur[v];
 61                 ee[id].cap -= aug[e];
 62                 ee[id^1].cap += aug[e];
 63                 aug[v] -= aug[e]; //修改可增广量,以后会用到
 64                 if (ee[id].cap == 0) u = v; //不回退到源点,仅回退到容量为0的弧的弧尾
 65             }
 66         }
 67         for (id = cur[u]; id != -1; id = ee[id].next)
 68         {   // 从当前弧开始查找允许弧
 69             v = ee[id].v;
 70             if (ee[id].cap > 0 && dis[u] == dis[v] + 1) //找到允许弧
 71             {
 72                 flag = true;
 73                 pre[v] = u;
 74                 cur[u] = id;
 75                 aug[v] = min(aug[u], ee[id].cap);
 76                 u = v;
 77                 break;
 78             }
 79         }
 80         if (flag == false)
 81         {
 82             if (--gap[dis[u]] == 0) break; /*gap优化层次树出现断层则结束算法*/
 83             mindis = n;
 84             cur[u] = head[u];
 85             for (id = head[u]; id != -1; id = ee[id].next)
 86             {
 87                 v = ee[id].v;
 88                 if (ee[id].cap > 0 && dis[v] < mindis)
 89                 {
 90                     mindis = dis[v];
 91                     cur[u] = id; //修改标号的同时修改当前弧
 92                 }
 93             }
 94             dis[u] = mindis + 1;
 95             gap[dis[u]]++;
 96             if (u != s) u = pre[u]; //回溯继续寻找允许弧
 97         }
 98     }
 99     return max_flow;
100 }
101 int N,M;
102 int A[maxn],B[maxn];
103 int a[maxn],b[maxn],w[maxn];
104 void solve(){
105     int s = N,t= s+1;
106     for(int i=0;i<N;++i){
107         addedge(i,t,A[i]);
108         addedge(s,i,B[i]);
109     }
110     for(int i=0;i<M;++i){
111         addedge(a[i]-1,b[i]-1,w[i]);
112         addedge(b[i]-1,a[i]-1,w[i]);
113     }
114     int ans = SAP(s,t,t+1);
115     printf("%d\n",ans);
116 }
117 int main (){
118     while(scanf("%d%d",&N,&M)!=EOF){
119         init();
120         for(int i=0;i<N;++i)scanf("%d%d",&A[i],&B[i]);
121         for(int i=0;i<M;++i)scanf("%d%d%d",&a[i],&b[i],&w[i]);
122         solve();
123     }
124 }

最小费用流:

bellman-ford:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <queue>
 7 #define maxn 1010
 8 #define maxm 1010
 9 #define INF 0x3f3f3f3f
10 using namespace std;
11 struct edge{int to,cap,cost,rev;};
12 int V; //顶点数
13 vector<edge> G[maxn];//邻接表
14 int dist[maxn];//最短距离
15 int prevv[maxn],preve[maxn];//最短路中前驱节点以及对应的边
16 void addedge(int from ,int to, int cap, int cost){
17     G[from].push_back((edge){to,cap,cost,G[to].size()});
18     G[to].push_back((edge){from,0,-cost,G[from].size()-1});
19 }
20
21 //求从s到t的流量为f的最小费用流,
22 //如果无法增广返回-1
23 //复杂度:O(F|V||E|)
24 int min_cost_flow(int s, int t,int f){
25     int res = 0;
26     while(f>0){
27         //利用bellman-ford求解最短路
28         fill (dist,dist+V,INF);
29         dist[s]=0;
30         bool update = true;
31         while(update){
32             update = false;
33             for(int v = 0; v<V; v++){
34                 if(dist[v]==INF)continue;
35                 for (int i=0;i<G[v].size();++i){
36                     edge &e =G[v][i];
37                     if(e.cap>0&&dist[e.to]>dist[v]+e.cost){
38                         dist[e.to]=dist[v]+e.cost;
39                         prevv[e.to]=v;
40                         preve[e.to]=i;
41                         update = true;
42                     }
43                 }
44             }
45         }
46         if (dist[t]==INF){
47             //无法再增广
48             return -1;
49         }
50
51         //沿着最短路尽量增广
52          int d = f;
53          for(int v = t; v!=s;v = prevv[v]){
54             d = min(d,G[prevv[v]][preve[v]].cap);
55          }
56          f-=d;
57          res+=d*dist[t];
58          for(int v = t;v!=s;v = prevv[v]){
59             edge &e = G[prevv[v]][preve[v]];
60             e.cap -=d;
61             G[v][e.rev].cap+=d;
62          }
63     }
64     return res;
65 }
66 int main (){
67     int n,m;
68     while(scanf("%d%d",&n,&m)!=EOF){
69         V=n+1;
70         for(int i=0;i<m;++i){
71             int a,b,c;
72             scanf("%d%d%d",&a,&b,&c);
73             addedge(a,b,1,c);
74             addedge(b,a,1,c);
75         }
76         int ans = min_cost_flow(1,n,2);
77         printf("%d\n",ans);
78     }
79 }

Dijkstra:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <queue>
 7 #define maxn 1010
 8 #define maxm 1010
 9 #define INF 0x3f3f3f3f
10 using namespace std;
11 typedef pair<int,int>P;//first 为最短距离,second为顶点编号
12 struct edge{int to,cap,cost,rev; };
13 int V; //顶点数
14 vector<edge> G[maxn];//邻接表
15 int dist[maxn];//最短距离
16 int h[maxn];//顶点的势
17 int prevv[maxn],preve[maxn];//最短路中前驱节点以及对应的边
18 void addedge(int from ,int to, int cap, int cost){
19     G[from].push_back((edge){to,cap,cost,G[to].size()});
20     G[to].push_back((edge){from,0,-cost,G[from].size()-1});
21 }
22
23 //求从s到t的流量为f的最小费用流,
24 //如果无法增广返回-1
25 //复杂度:O(F|V||E|)
26 int min_cost_flow(int s, int t,int f){
27     int res = 0;
28     fill(h,h+V,0);
29     while(f>0){
30         //利用Dijkstra更新h
31         priority_queue<P, vector<P>,greater<P> >q;
32         fill (dist,dist+V,INF);
33         dist[s]=0;
34         q.push(P(0,s));
35         while(!q.empty()){
36             P p = q.top();
37             q.pop();
38             int v = p.second;
39             if (dist[v]<p.first)continue;
40             for (int i=0;i<G[v].size();++i){
41                 edge &e = G[v][i];
42                 if (e.cap>0&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to]){
43                         dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
44                         prevv[e.to]=v;
45                         preve[e.to]=i;
46                         q.push(P(dist[e.to],e.to));
47                 }
48             }
49         }
50         if (dist[t]==INF){
51             //无法再增广
52             return -1;
53         }
54         for (int v=0;v<V;++v){
55             h[v]+=dist[v];
56         }
57
58         //沿着最短路尽量增广
59          int d = f;
60          for(int v = t; v!=s;v = prevv[v]){
61             d = min(d,G[prevv[v]][preve[v]].cap);
62          }
63          f-=d;
64          res+=d*h[t];
65          for(int v = t;v!=s;v = prevv[v]){
66             edge &e = G[prevv[v]][preve[v]];
67             e.cap -=d;
68             G[v][e.rev].cap+=d;
69          }
70     }
71     return res;
72 }
73
74 int main (){
75     int n,m;
76     while(scanf("%d%d",&n,&m)!=EOF){
77         V=n+1;
78         for(int i=0;i<m;++i){
79             int a,b,c;
80             scanf("%d%d%d",&a,&b,&c);
81             addedge(a,b,1,c);
82             addedge(b,a,1,c);
83         }
84         int ans = min_cost_flow(1,n,2);
85         printf("%d\n",ans);
86     }
87 }

时间: 2024-11-07 19:00:26

图论算法----网络流的相关文章

基础图论算法导引

ACM中常用图论算法 1. 拓扑排序 -> 拓扑排序的原理及其实现 2. 最短路径算法 -> 最短路算法总结 差分约束系统 -> 差分约束 前k短路 -> 前K短路径问题 3. 最小生成树问题扩展 -> 最?小?生?成?树?问?题?的?拓?展  最优比率生成树 -> 最优比率生成树 最小k度限制生成树 -> IOI2004国家集训队论文,由汪汀所著(网盘内有) 或者刘汝佳的黑书内有 裸题 poj1639 题解 4. 二分图匹配 -> 二分图的最大匹配.完美匹

【图论】网络流总结

[图论]网络流总结 最大流部分 网络流题目的关键:看出是网络流而且确定正确的模型 最大流算法:用来解决从源点s到汇点t,整个网络最多能输送多少流量的题目 模板: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int MAXNODE = 105 * 2; const int MAXEDGE = 10000

图论算法的数学模型

目录 图论算法的数学模型 引入:最短路的数学形式 最小割的数学形式 一些没用的总结 图论算法的数学模型 今天听敦敦敦的课总结一下... 前置芝士:网络流,最小割 引入:最短路的数学形式 松弛操作: 对于一条边\((u,v,w)\),\(\text {if}~(dis_u+w(u,v)<dis_v)~\text{then}~dis_v=dis_u+w(u,v)\) 所以对于求出来的dis,有\(dis_v\leq dis_u+w(u,v)\)对吧... 那么这和差分约束中\(x_i-x_j\leq

图论算法之最短路径

图论算法之最短路径 作者:jasonkent27 转载请注明出处:www.cnblogs.com/jasonkent27 1. 前言 1.1 最短路引入 小明和小天现在住在海口(C1),他们俩计划暑假到三亚(C4)玩一趟,在海口和三亚之间有许多中间城市(文昌,临高,乐东,万宁...)图中的边上的数字是他们到达该城市必须的花费,现在需要你帮他们俩找出一条从海口到三亚的最省钱的路径出来. 等等,图中的边的weight怎么会有负的呢?你暂且可以这么理解吧.图中的边上的weight可以当作他们旅途中必须

图论算法----强连通

poj 2186 Popular Cows 分析:直接求一下强连通分量,对于同一个强连通分量里面的结点状态是相同的,要求有多少个人被其他所有的人都认可,只有可能是拓扑排序的最后一个强连通的结点个数,判断一下其他节点是否都可以到该联通分量就ok了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <set> 5 #include <algorithm>

图论算法(5) --- 双向广搜求最短路(Bidirectional Breadth First Search)

我们知道,在图论算法中,求最短路是最基本的问题.在求最短路的问题中,应用双向广度优先搜索算法,又是一个较为高效而又简单的算法.所谓双向广度优先搜索,其实根本的核心还是BFS,只不过它是从起点和终点两头同时搜索,大大提高了搜索效率,又节省了搜索空间.广搜大家知道当然是用队列来实现了,在这里,要注意的问题就是,我们必须按层搜索,正向队列处理一层,接着去处理反向队列的一层,按层交替进行,而不是按节点交替进行,这点需要注意,其他的也就很简单了,代码中附有注释,如有问题请留言. package simil

图论算法-Tarjan模板 【缩点;割顶;双连通分量】

图论算法-Tarjan模板 [缩点:割顶:双连通分量] 为小伙伴们总结的Tarjan三大算法 Tarjan缩点(求强连通分量) int n; int low[100010],dfn[100010]; bool ins[100010]; int col[100010];//记录每个点所属强连通分量(即染色) vector<int> map[100010]; stack<int> st; int tot;//时间戳 int colnum;//记录强连通分量个数 void tarjan(

再谈排序与图论算法

排序 1.主存能放下的数据进行排序称为内部排序,反之称为外部排序(磁盘上).2.任何进行交换相邻元素进行排序的算法均需要O(N2)的复杂度,任何进行比较的排序算法至少需要O(N*log(N))的算法复杂度. 3.堆排序和归并排序的时间复杂度平均和最坏均为O(N*log(N)) 4.Java中执行一次对象比较是比较昂贵的,移动则是相对节省的,因此归并排序是java的默认泛型排序算法.C++中默认的是快速排序,比较耗费小:快排对于基本类型均具有最快速度.快速排序选取枢纽元的时候采用三数取中,切勿采用

【WIP_S9】图论算法

创建: 2018/06/01 图的概念 有向边 有向图 无向边 无向图 点的次数: 点连接的边的数量 闭路: 起点和重点一样 连接图: 任意两点之间都可到达 无闭路有向图: 没有闭路的有向图 森林: 互素的树的集合 生成树: 含有图里所有点的树 生成树林: 所有生成树的并集         图论算法的应用     ● 电路的元件关系 ● 交通网 ● 电脑网络(本地网络, 互联网, web等) ● 数据库(实体关系图(ER图))