网络流 dicnic sap 2种算法详细解释 以及例题POJ1459
分类: ACM模板 网络流
2013-08-18 17:22
282人阅读
收藏
举报
http://blog.sina.com.cn/s/blog_691ce2b701016jfv.html
http://blog.sina.com.cn/s/blog_691ce2b70101843h.html
题目大意:
给几个发电站,给几个消耗站,再给几个转发点。
发电站只发电,消耗站只消耗电,转发点只是转发电,再给各个传送线的传电能力。
问你消耗站能获得的最多电是多少
思路:建立一个超级源点和超级汇点,把发电站相连起来,消耗站连起来 然后就是模版的力量了
在此也讲了下dinic的原理:
求最大流的本质,就是不停的寻找增广路径。直到找不到增广路径为止。
对于这个一般性的过程,Dinic算法的优化如下:
(1)
Dinic算法首先对图进行一次BFS,然后在BFS生成的层次图中进行多次DFS。
层次图的意思就是,只有在BFS树中深度相差1的节点才是连接的。
这就切断了原有的图中的许多不必要的连接。很牛逼!
这是需要证明的,估计证明也很复杂。
(2)
除此之外,每次DFS完后,会找到路径中容量最小的一条边。
在这条边之前的路径的容量是大于等于这条边的容量的。
那么从这条边之前的点,可能引发出别的增广路径。
比如说
S -> b -> c-> d -> T 是一条增广路径,容量最小的边是 b-> c。
可能存在一条 S -> b -> e ->f -> g -> T 这样的增广路径。
这样的话,在找到第一条增广路径后,只需要回溯到 b 点,就可以继续找下去了。
这样做的好处是,避免了找到一条路径就从头开始寻找另外一条的开销。
也就是再次从 S 寻找到 b 的开销。
这个过程看似复杂,但是代码实现起来很优雅,因为它的本质就是回溯!
(3)
在同一次 DFS 中。如果从一个点引发不出任何的增广路径,就将这个点在层次图中抹去。
- #include <stdio.h>
- #include <string.h>
- #define VM 2000
- #define EM 205500
- #define inf 0x3f3f3f3f
- struct Edge
- {
- int frm,to,cap,next;
- }edge[EM];
-
- int head[VM],dep[VM],ep;
- void addedge (int cu,int cv,int cw)
- {
- edge[ep].frm = cu;
- edge[ep].to = cv;
- edge[ep].cap = cw;
- edge[ep].next = head[cu];
- head[cu] = ep;
- ep ++;
- edge[ep].frm = cv;
- edge[ep].to = cu;
- edge[ep].cap = 0;
- edge[ep].next = head[cv];
- head[cv] = ep;
- ep ++;
- }
-
- int BFS (int src,int des)
- {
- int que[VM],i,front = 0,rear = 0;
- memset (dep,-1,sizeof(dep));
- que[rear++] = src;
- dep[src] = 0;
- while (front != rear)
- {
- int u = que[front++];
- front = front%VM;
- for (i = head[u];i != -1;i = edge[i].next)
- {
- int v = edge[i].to;
- if (edge[i].cap > 0&&dep[v] == -1)
- {
- dep[v] = dep[u] + 1;
- que[rear ++] = v;
- rear = rear % VM;
- if (v == des)
- return 1;
- }
- }
- }
- return 0;
- }
- int dinic (int src,int des)
- {
- int i,res = 0,top;
- int stack[VM];
- int cur[VM];
- while (BFS(src,des))
- {
- memcpy (cur,head,sizeof (head));
- int u = src;
- top = 0;
- while (1)
- {
- if (u == des)
- {
- int min = inf,loc ;
- for (i = 0;i < top;i ++)
- if (min > edge[stack[i]].cap)
- {
- min = edge[stack[i]].cap;
- loc = i;
- }
- for (i = 0;i < top;i ++)
- {
- edge[stack[i]].cap -= min;
- edge[stack[i]^1].cap += min;
- }
- res += min;
- top = loc;
- u = edge[stack[top]].frm;
- }
- for (i = cur[u];i != -1;cur[u] = i = edge[i].next)
- if (edge[i].cap != 0&&dep[u] + 1 == dep[edge[i].to])
- break;
- if (cur[u] != -1)
- {
- stack[top ++] = cur[u];
- u = edge[cur[u]].to;
- }
- else
- {
- if (top == 0)
- break;
- dep[u] = -1;
- u = edge[stack[--top]].frm;
- }
- }
- }
- return res;
- }
- int main ()
- {
- int np,nc,m,v1,v2,w,n;
- int src,des;
- char str[20];
- while (scanf ("%d%d%d%d",&n,&np,&nc,&m)!=EOF)
- {
- ep = 0;
- src = n;
- des = n+1;
- memset (head,-1,sizeof(head));
- while (m --)
- {
- scanf ("%s",str);
- sscanf (str,"(%d,%d)%d",&v1,&v2,&w);
- addedge (v1,v2,w);
- }
- while (np --)
- {
- scanf ("%s",str);
- sscanf (str,"(%d)%d",&v2,&w);
- addedge (src,v2,w);
- }
- while (nc--)
- {
- scanf ("%s",str);
- sscanf (str,"(%d)%d",&v1,&w);
- addedge (v1,des,w);
- }
- int ans = dinic (src,des);
- printf ("%d\n",ans);
- }
- return 0;
- }
sap 算法 注意上面的n有用
- #include <stdio.h>
- #include <string.h>
- const int VM = 110, EM = 20500, inf = 0x3f3f3f3f;
- struct Edge
- {
- int to, frm, nxt, cap;
- }edge[EM];
-
- int head[VM], ep, n, src, des;
- int dep[VM], gap[VM];
-
- void addedge(int u, int v, int c)
- {
- edge[ep].frm = u;
- edge[ep].to = v;
- edge[ep].cap = c;
- edge[ep].nxt = head[u];
- head[u] = ep++;
- edge[ep].frm = v;
- edge[ep].to = u;
- edge[ep].cap = 0;
- edge[ep].nxt = head[v];
- head[v] = ep++;
- }
-
- void BFS()
- {
- memset(dep, -1, sizeof(dep));
- memset(gap, 0, sizeof(gap));
- gap[0] = 1;
- int que[VM], front = 0, rear = 0;
- dep[des] = 0;
- que[rear++] = des;
- int u, v;
- while (front != rear)
- {
- u = que[front++];
- front = front%VM;
- for (int i=head[u]; i!=-1; i=edge[i].nxt)
- {
- v = edge[i].to;
- if (edge[i].cap != 0 || dep[v] != -1)
- continue;
- que[rear++] = v;
- rear = rear % VM;
- ++gap[dep[v] = dep[u] + 1];
- }
- }
- }
-
- int Sap()
- {
- int res = 0;
- BFS();
- int cur[VM];
- int stack[VM], top = 0;
- memcpy(cur, head, sizeof(head));
- int u = src, i;
- while (dep[src] < n)
- {
- if (u == des)
- {
- int temp = inf, inser = n;
- for (i=0; i!=top; ++i)
- if (temp > edge[stack[i]].cap)
- {
- temp = edge[stack[i]].cap;
- inser = i;
- }
- for (i=0; i!=top; ++i)
- {
- edge[stack[i]].cap -= temp;
- edge[stack[i]^1].cap += temp;
- }
- res += temp;
- top = inser;
- u = edge[stack[top]].frm;
- }
-
- if (dep[u] != 0 && gap[dep[u] -1] == 0)
- break;
- for (i = cur[u]; i != -1; i = edge[i].nxt)
- if (dep[edge[i].to] != -1)
- if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1)
- break;
-
- if (i != -1)
- {
- cur[u] = i;
- stack[top++] = i;
- u = edge[i].to;
- }
- else
- {
- int min = n;
- for (i = head[u]; i != -1; i = edge[i].nxt)
- {
- if (edge[i].cap == 0)
- continue;
- if (min > dep[edge[i].to])
- {
- min = dep[edge[i].to];
- cur[u] = i;
- }
- }
- --gap[dep[u]];
- ++gap[dep[u] = min + 1];
- if (u != src)
- u = edge[stack[--top]].frm;
- }
- }
- return res;
- }
-
- int main()
- {
- int i, np, nc, m;
- char str[10];
- while (scanf("%d %d %d %d", &n, &np, &nc, &m) != EOF)
- {
- ep = 0;
- memset(head, -1, sizeof(head));
- int u, v, c;
- src = n, des = n + 1;
- n += 2;
- for (i=0; i!=m; ++i)
- {
- scanf("%stack", str);
- sscanf(str, "(%d,%d)%d", &u, &v, &c);
- addedge(u, v, c);
- }
- for (i=0; i!=np; ++i)
- {
- scanf("%stack", str);
- sscanf(str, "(%d)%d", &v, &c);
- addedge(src, v, c);
- }
- for (i=0; i!=nc; ++i)
- {
- scanf("%stack", str);
- sscanf(str, "(%d)%d", &u, &c);
- addedge(u, des, c);
- }
- printf("%d\n", Sap());
- }
- return 0;
- }
Secret Milking Machine
Time Limit: 1000MS |
|
Memory Limit: 65536K |
Total Submissions: 8189 |
|
Accepted: 2485 |
Description
Farmer John is constructing a new milking machine and wishes to keep it secret as long as possible. He has hidden in it deep within his farm and needs to be able to get to the machine without being detected. He must make a total of T (1 <= T <= 200) trips to the machine during its construction. He has a secret tunnel that he uses only for the return trips.
The farm comprises N (2 <= N <= 200) landmarks (numbered 1..N) connected by P (1 <= P <= 40,000) bidirectional trails (numbered 1..P) and with a positive length that does not exceed 1,000,000. Multiple trails might join a pair of landmarks.
To minimize his chances of detection, FJ knows he cannot use any trail on the farm more than once and that he should try to use the shortest trails.
Help FJ get from the barn (landmark 1) to the secret milking machine (landmark N) a total of T times. Find the minimum possible length of the longest single trail that he will have to use, subject to the constraint that he use no trail more than once. (Note well: The goal is to minimize the length of the longest trail, not the sum of the trail lengths.)
It is guaranteed that FJ can make all T trips without reusing a trail.
Input
* Line 1: Three space-separated integers: N, P, and T
* Lines 2..P+1: Line i+1 contains three space-separated integers, A_i, B_i, and L_i, indicating that a trail connects landmark A_i to landmark B_i with length L_i.
Output
* Line 1: A single integer that is the minimum possible length of the longest segment of Farmer John's route.
Sample Input
7 9 2
1 2 2
2 3 5
3 7 5
1 4 1
4 3 1
4 5 7
5 7 1
1 6 3
6 7 3
Sample Output
5
Hint
Farmer John can travel trails 1 - 2 - 3 - 7 and 1 - 6 - 7. None of the trails travelled exceeds 5 units in length. It is impossible for Farmer John to travel from 1 to 7 twice without using at least one trail of length 5.
Huge input data,scanf is recommended.
Source
USACO 2005 February Gold
题意:
题意:FJ有N块地,这些地之间有P条双向路,每条路的都有固定的长度l。现在要你找出从第1块地到第n块地的T条不同路径,每条路径上的路不能与先前的路径重复,问这些路径中的最长路的最小是多少。
思路:二分答案+网络流判定。
二分枚举最大边权,重新建图,只保存权不超过最大边权的边。即如果边的长度小于等于我们规定的最大边权 则添加这条边 权值为1, 否则标记为0
然后在网络中起点终点间的容量是原图中的路径数,判断最大流是否>=T
只需要对模板就行修改下 之后二分即可 只需要修改添加边的地方 因为本题是双向边 所以添加的边以及其反方向边 都应该权值为cw
- #include <stdio.h>
- #include <string.h>
- #define VM 222
- #define EM 81111*2
- #define inf 0x3f3f3f3f
- struct Edge
- {
- int frm,to,cap,next;
- }edge[EM];
-
- int head[VM],dep[VM],ep,n;
- void addedge (int cu,int cv,int cw)
- {
- edge[ep].frm = cu;
- edge[ep].to = cv;
- edge[ep].cap = cw;
- edge[ep].next = head[cu];
- head[cu] = ep;
- ep ++;
- edge[ep].frm = cv;
- edge[ep].to = cu;
- edge[ep].cap = cw;
- edge[ep].next = head[cv];
- head[cv] = ep;
- ep ++;
- }
-
- int BFS (int src,int des)
- {
- int que[VM],i,front = 0,rear = 0;
- memset (dep,-1,sizeof(dep));
- que[rear++] = src;
- dep[src] = 0;
- while (front != rear)
- {
- int u = que[front++];
- front = front%VM;
- for (i = head[u];i != -1;i = edge[i].next)
- {
- int v = edge[i].to;
- if (edge[i].cap > 0&&dep[v] == -1)
- {
- dep[v] = dep[u] + 1;
- que[rear ++] = v;
- rear = rear % VM;
- if (v == des)
- return 1;
- }
- }
- }
- return 0;
- }
- int dinic (int src,int des)
- {
- int i,res = 0,top;
- int stack[VM];
- int cur[VM];
- while (BFS(src,des))
- {
- memcpy (cur,head,sizeof (head));
- int u = src;
- top = 0;
- while (1)
- {
- if (u == des)
- {
- int min = inf,loc ;
- for (i = 0;i < top;i ++)
- if (min > edge[stack[i]].cap)
- {
- min = edge[stack[i]].cap;
- loc = i;
- }
- for (i = 0;i < top;i ++)
- {
- edge[stack[i]].cap -= min;
- edge[stack[i]^1].cap += min;
- }
- res += min;
- top = loc;
- u = edge[stack[top]].frm;
- }
- for (i = cur[u];i != -1;cur[u] = i = edge[i].next)
- if (edge[i].cap != 0&&dep[u] + 1 == dep[edge[i].to])
- break;
- if (cur[u] != -1)
- {
- stack[top ++] = cur[u];
- u = edge[cur[u]].to;
- }
- else
- {
- if (top == 0)
- break;
- dep[u] = -1;
- u = edge[stack[--top]].frm;
- }
- }
- }
- return res;
- }
- struct IN
- {
- int x,y,c;
- }q[EM];
- int sovle(int mid,int src,int des,int m,int k)
- {
- ep = 0;
- memset (head,-1,sizeof(head));
- for(int i=0;i<m;i++)
- {
- if(q[i].c<=mid)
- addedge(q[i].x,q[i].y,1);
-
-
- }
- if(dinic (src,des)>=k) return 1;
- return 0;
- }
- int main ()
- {
- int n,m,v1,v2,w,k,i;
- int src,des;
- while (scanf ("%d %d %d",&n,&m,&k)!=EOF)
- {
-
- src=1;des=n;
-
- for(i=0;i<m;i++)
- {
- scanf("%d %d %d",&v1,&v2,&w);
- q[i].x=v1;q[i].y=v2;q[i].c=w;
- }
- int left,right,mid,ans=-1;
- left=0;right=1000000;
- while(left<=right)
- {
- mid=(left+right)/2;
- if(sovle(mid,src,des,m,k))
- {
- ans=mid;
- right=mid-1;
- }
- else left=mid+1;
- }
- printf ("%d\n",ans);
- }
- return 0;
- }
Sap 算法
- #include <stdio.h>
- #include <string.h>
- #define VM 222
- #define EM 81111*2
- #define inf 0x3f3f3f3f
-
-
- struct Edge
- {
- int to, frm, nxt, cap;
- }edge[EM];
-
- int head[VM], ep, n, src, des;
- int dep[VM], gap[VM];
-
- void addedge(int u, int v, int c)
- {
- edge[ep].frm = u;
- edge[ep].to = v;
- edge[ep].cap = c;
- edge[ep].nxt = head[u];
- head[u] = ep++;
- edge[ep].frm = v;
- edge[ep].to = u;
- edge[ep].cap = 0;
- edge[ep].nxt = head[v];
- head[v] = ep++;
- }
-
- void BFS()
- {
- memset(dep, -1, sizeof(dep));
- memset(gap, 0, sizeof(gap));
- gap[0] = 1;
- int que[VM], front = 0, rear = 0;
- dep[des] = 0;
- que[rear++] = des;
- int u, v;
- while (front != rear)
- {
- u = que[front++];
- front = front%VM;
- for (int i=head[u]; i!=-1; i=edge[i].nxt)
- {
- v = edge[i].to;
- if (edge[i].cap != 0 || dep[v] != -1)
- continue;
- que[rear++] = v;
- rear = rear % VM;
- ++gap[dep[v] = dep[u] + 1];
- }
- }
- }
-
- int Sap()
- {
- int res = 0;
- BFS();
- int cur[VM];
- int stack[VM], top = 0;
- memcpy(cur, head, sizeof(head));
- int u = src, i;
- while (dep[src] < n)
- {
- if (u == des)
- {
- int temp = inf, inser = n;
- for (i=0; i!=top; ++i)
- if (temp > edge[stack[i]].cap)
- {
- temp = edge[stack[i]].cap;
- inser = i;
- }
- for (i=0; i!=top; ++i)
- {
- edge[stack[i]].cap -= temp;
- edge[stack[i]^1].cap += temp;
- }
- res += temp;
- top = inser;
- u = edge[stack[top]].frm;
- }
-
- if (dep[u] != 0 && gap[dep[u] -1] == 0)
- break;
- for (i = cur[u]; i != -1; i = edge[i].nxt)
- if (dep[edge[i].to] != -1)
- if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1)
- break;
-
- if (i != -1)
- {
- cur[u] = i;
- stack[top++] = i;
- u = edge[i].to;
- }
- else
- {
- int min = n;
- for (i = head[u]; i != -1; i = edge[i].nxt)
- {
- if (edge[i].cap == 0)
- continue;
- if (min > dep[edge[i].to])
- {
- min = dep[edge[i].to];
- cur[u] = i;
- }
- }
- --gap[dep[u]];
- ++gap[dep[u] = min + 1];
- if (u != src)
- u = edge[stack[--top]].frm;
- }
- }
- return res;
- }
-
-
-
-
- struct IN
- {
- int x,y,c;
- }q[EM];
- int sovle(int mid,int m,int k)
- {
-
- ep = 0;
- memset (head,-1,sizeof(head));
- for(int i=0;i<m;i++)
- {
- if(q[i].c<=mid)
- {
- addedge(q[i].x,q[i].y,1);
- addedge(q[i].y,q[i].x,1);
- }
- }
- if(Sap()>=k) return 1;
- return 0;
- }
- int main ()
- {
- int m,v1,v2,w,k,i;
- while (scanf ("%d %d %d",&n,&m,&k)!=EOF)
- {
- src=1;des=n;
- for(i=0;i<m;i++)
- {
- scanf("%d %d %d",&v1,&v2,&w);
- q[i].x=v1;q[i].y=v2;q[i].c=w;
- }
- int left,right,mid,ans=-1;
- left=0;right=1000000;
- while(left<=right)
- {
- mid=(left+right)/2;
- if(sovle(mid,m,k))
- {
- ans=mid;
- right=mid-1;
- }
- else left=mid+1;
- }
- printf ("%d\n",ans);
- }
- return 0;
- }