题意:现在有m个池塘(从1到m开始编号,1为源点,m为汇点),及n条有向水渠,给出这n条水渠所连接的点和所能流过的最大流量,求从源点到汇点能流过的最大流量
Dinic
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include <cstdio> 5 #include <queue> 6 using namespace std; 7 const int N = 202; 8 const int INF = 0x3f3f3f3f; 9 int m,n,tot; 10 int head[N],level[N]; 11 struct node 12 { 13 int t,next,w; 14 }edge[N<<2]; 15 16 17 void init() 18 { 19 tot=-1; 20 memset(head,-1, sizeof(head)); 21 } 22 23 void add(int s,int t,int w) 24 { 25 edge[++tot].t=t,edge[tot].w=w,edge[tot].next=head[s],head[s]=tot; 26 edge[++tot].t=s,edge[tot].w=0,edge[tot].next=head[t],head[t]=tot; 27 } 28 29 bool bfs() 30 { 31 memset(level,0,sizeof(level)); 32 queue<int> q; 33 while(!q.empty())q.pop(); 34 q.push(1); 35 level[1]=1; 36 while(q.size()) 37 { 38 int u=q.front();q.pop(); 39 for(int i=head[u];i!=-1;i=edge[i].next) 40 { 41 if(edge[i].w>0&&level[edge[i].t]==0) 42 { 43 q.push(edge[i].t); 44 level[edge[i].t]=level[u]+1; 45 } 46 if(level[m]!=0)return 1; 47 } 48 } 49 return 0; 50 } 51 52 int dfs(int s,int t, int flow) 53 { 54 if(s==t)return flow; 55 for(int i=head[s];i!=-1;i=edge[i].next) 56 { 57 if(edge[i].w>0&&level[edge[i].t]==level[s]+1) 58 { 59 int k = dfs(edge[i].t,t,min(flow,edge[i].w)); 60 if(k>0) 61 { 62 edge[i].w-=k; 63 edge[i^1].w+=k; 64 return k; 65 } 66 } 67 } 68 return 0; 69 } 70 // 71 void dinic() 72 { 73 int flow=0; 74 while(bfs()) // 寻找最短增广路,分层图 75 { 76 int f=0; 77 while((f=dfs(1,m,INF))>0)flow+=f; // 在分层图上增广 78 } 79 cout<<flow<<endl; 80 } 81 int main() 82 { 83 while(~scanf("%d%d",&n,&m)) 84 { 85 init(); 86 while(n--) 87 { 88 int a,b,c; 89 scanf("%d%d%d",&a,&b,&c); 90 add(a,b,c); 91 } 92 dinic(); 93 } 94 return 0; 95 }
建图的另一种方法,上面有两种邻接表的方法,一种是单纯用数组模拟,可以运用异或操作反向边;另一个是vector模拟,反向边做特别记录
1 struct edge 2 { 3 int to,cap,rev;// 反向边 4 }; 5 vector<edge> g[maxn]; 6 int level[maxn]; 7 8 void add_edge(int from,int to,int cap) 9 { 10 //最后一个元素是反向边的索引,便于快速查找 11 g[from].push_back((edge){to,cap,g[to].size()}); 12 g[to].push_back((edge){from,0,g[from].size()-1}); 13 }
Ford_Fulkerson