【板子】网络流
最大流:
例题:http://poj.org/problem?id=1273
dinic:
1 //dinic 2 3 #include <algorithm> 4 #include <iostream> 5 #include <string.h> 6 #include <cstdio> 7 #include <queue> 8 using namespace std; 9 const int inf = 0x3f3f3f3f; 10 const int maxn = 205; 11 const int maxm = maxn*maxn; 12 struct node{int w; int v, next;} edge[maxm]; 13 int pre[maxn], rec[maxn], head[maxn], block[maxn]; 14 int dis[maxn]; 15 int n, m, no; 16 int S, T; 17 queue<int> q; 18 inline void init(){ 19 no = 0; 20 memset(head, -1, sizeof head); 21 } 22 inline void add(int u, int v, int w){ 23 edge[no].v = v; edge[no].w = w; 24 edge[no].next = head[u]; head[u] = no++; 25 edge[no].v = u; edge[no].w = 0; 26 edge[no].next = head[v]; head[v] = no++; 27 } 28 void reset(int S, int T){ 29 memset(dis, 0x3f, sizeof dis); 30 memset(block, 0, sizeof block); 31 q.push(S); dis[S] = 0; 32 while(!q.empty()){ 33 int top = q.front(); q.pop(); 34 for(int k = head[top]; k != -1; k = edge[k].next) 35 if(dis[edge[k].v] == inf && edge[k].w) 36 dis[edge[k].v] = dis[top]+1, q.push(edge[k].v); 37 } 38 } 39 int dinic(int S, int T){ 40 int ans = 0, flow = inf; 41 int top = S; 42 reset(S, T); pre[S] = S; 43 while(dis[T] != inf){ 44 int k, tmp; 45 for(k = head[top]; k != -1; k = edge[k].next){ 46 if(edge[k].w && dis[edge[k].v]==dis[top]+1 && 47 !block[edge[k].v]) break; 48 } 49 if(k != -1){ 50 tmp = edge[k].v; 51 flow = min(flow, edge[k].w); 52 pre[tmp] = top, rec[tmp] = k; 53 top = tmp; 54 if(top == T){ 55 ans += flow; tmp = -1; 56 for(; top != S; top = pre[top]){ 57 edge[rec[top]].w -= flow; 58 edge[rec[top]^1].w += flow; 59 if(!edge[rec[top]].w) tmp = top; 60 } 61 flow = inf; 62 if(tmp != -1){ 63 top = pre[tmp]; 64 for(; top != S; top = pre[top]) 65 flow = min(flow, edge[rec[top]].w); 66 top = pre[tmp]; 67 } 68 } 69 } 70 else{ 71 block[top] = 1; 72 top = pre[top]; 73 if(block[S]) reset(S, T); 74 } 75 } 76 return ans; 77 } 78 void mapping(){ 79 int u, v, w; 80 for(int i = 1; i <= m; ++i){ 81 scanf("%d %d %d", &u, &v, &w); 82 add(u, v, w); 83 } 84 } 85 int main(){ 86 while(~scanf("%d %d", &m, &n)){ 87 S = 1, T = n; 88 init(); 89 mapping(); 90 printf("%d\n", dinic(S, T)); 91 } 92 return 0; 93 }
sap:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<cstdlib> 6 #include<string> 7 #include<queue> 8 #include<algorithm> 9 using namespace std; 10 11 const int N=100010; 12 const int M=400010; 13 const int inf=0xfffffff; 14 15 int n,m,cnt; 16 17 struct Edge{ 18 int v , cap , next; 19 } edge[M]; 20 21 int head[N],pre[N],d[N],numd[N];//分别为链表的头指针,每个点的前驱,每个点的d值,以及标号为d[i] 的点的个数 22 int cur_edge[N];//从每个点出发满足d[i] = d[j] + 1的边的地址 , 插入边时的计数,源点与汇点 23 24 void addedge(int u,int v,int c){ 25 26 edge[cnt].v = v; 27 edge[cnt].cap = c; 28 edge[cnt].next = head[u]; 29 head[u] = cnt++; 30 31 edge[cnt].v = u; 32 edge[cnt].cap = 0; 33 edge[cnt].next = head[v]; 34 head[v] = cnt++; 35 } 36 37 void bfs(int s){ //先用广度优先算出每个点的d值 38 memset(numd,0,sizeof(numd)); 39 for(int i=1; i<=n; i++) 40 numd[ d[i] = n ]++; 41 d[s] = 0; 42 numd[n]--; 43 numd[0]++; 44 queue<int> Q; 45 Q.push(s); 46 47 while(!Q.empty()){ 48 int v=Q.front(); 49 Q.pop(); 50 51 int i=head[v]; 52 while(i != -1){ 53 int u=edge[i].v; 54 55 if(d[u]<n){ 56 i=edge[i].next; 57 continue ; 58 } 59 60 d[u]=d[v]+1; 61 numd[n]--; 62 numd[d[u]]++; 63 Q.push(u); 64 i=edge[i].next; 65 } 66 } 67 } 68 69 int SAP(int s,int t){ 70 for(int i = 1; i <= n; i++) 71 cur_edge[i] = head[i]; //当前满足d[i] = d[j] + 1的边的为第一条边 72 int max_flow=0; 73 bfs(t); 74 int u = s ;//从源点搜一条到汇点的增广路 75 while(d[s]<n){//就算所有的点连成一条线源点的d值也是最多是n-1 76 if(u == t){//如果找到一条增广路径 77 int cur_flow = inf,neck;//找到那条瓶颈边 78 for(int from = s; from != t; from = edge[cur_edge[from]].v){ 79 if(cur_flow > edge[cur_edge[from]].cap){ 80 neck = from; 81 cur_flow = edge[cur_edge[from]].cap; 82 } 83 } 84 85 for(int from = s; from != t; from = edge[cur_edge[from]].v){ //修改增广路上的边的容量 86 int tmp = cur_edge[from]; 87 edge[tmp].cap -= cur_flow; 88 edge[tmp^1].cap += cur_flow; 89 } 90 max_flow += cur_flow;//累加计算最大流 91 u = neck;//下一次搜索直接从瓶颈边的前一个节点搜起 92 } 93 94 int i; 95 for(i = cur_edge[u]; i != -1; i = edge[i].next) //从当前点开始找一条允许弧 96 if(edge[i].cap && d[u] == d[edge[i].v]+1)//如果找到跳出循环 97 break; 98 99 if(i!=-1){//找到一条允许弧 100 cur_edge[u] = i;//从点u出发的允许弧的地址 101 pre[edge[i].v] = u;//允许弧上下一个点的前驱为u 102 u = edge[i].v;//u变成下一个点继续搜直到搜出一条增广路 103 } 104 else{//如果没有搜到允许弧 105 numd[d[u]]--; //d[u]将被修改所以numd[d[u]]减一 106 if(!numd[d[u]]) break; //如果没有点的d值为d[u]则不可能再搜到增广路结束搜索 107 cur_edge[u] = head[u]; //当前点的允许弧为第一条边 108 int tmp = n; 109 for(int j = head[u]; j != -1; j = edge[j].next) //搜与u相连的点中d值最小的 110 if(edge[j].cap && tmp > d[edge[j].v]) 111 tmp = d[edge[j].v]; 112 113 d[u] = tmp+1; //修改d[u] 114 numd[d[u]]++; 115 if(u != s) 116 u = pre[u];//从u的前驱搜,因为从u没有搜到允许弧 117 } 118 } 119 return max_flow; 120 } 121 inline void pre_init(){ 122 cnt = 0; 123 memset(head, -1, sizeof head); 124 } 125 126 void mapping(){ 127 int u, v, w; 128 for(int i = 1; i <= m; ++i){ 129 scanf("%d %d %d", &u, &v, &w); 130 addedge(u, v, w); 131 } 132 } 133 134 int main(){ 135 while(~scanf("%d%d",&m,&n)){ 136 pre_init(); 137 mapping(); 138 int s,t; 139 s = 1;t = n; 140 int ans = SAP(s,t); 141 printf("%d\n",ans); 142 } 143 return 0; 144 }