网络流 dicnic sap 2种算法详细解释

 

网络流 dicnic sap 2种算法详细解释 以及例题POJ1459

分类: ACM模板 网络流   282人阅读  评论(0)  收藏  举报

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 中。如果从一个点引发不出任何的增广路径,就将这个点在层次图中抹去。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #define VM 2000  
  4. #define EM 205500  
  5. #define inf 0x3f3f3f3f  
  6. struct Edge  
  7. {  
  8.     int frm,to,cap,next;  
  9. }edge[EM];  
  10.   
  11. int head[VM],dep[VM],ep;     //dep为点的层次  
  12. void addedge (int cu,int cv,int cw)  //第一条边下标必须为偶数  
  13. {  
  14.     edge[ep].frm = cu;  
  15.     edge[ep].to = cv;  
  16.     edge[ep].cap = cw;  
  17.     edge[ep].next = head[cu];  
  18.     head[cu] = ep;  
  19.     ep ++;  
  20.     edge[ep].frm = cv;  
  21.     edge[ep].to = cu;  
  22.     edge[ep].cap = 0;  
  23.     edge[ep].next = head[cv];  
  24.     head[cv] = ep;  
  25.     ep ++;  
  26. }  
  27.   
  28. int BFS (int src,int des)     //求出层次图  
  29. {  
  30.     int que[VM],i,front = 0,rear = 0;  
  31.     memset (dep,-1,sizeof(dep));  
  32.     que[rear++] = src;  
  33.     dep[src] = 0;  
  34.     while (front != rear)  
  35.     {  
  36.         int u = que[front++];  
  37.         front = front%VM;  
  38.         for (i = head[u];i != -1;i = edge[i].next)  
  39.         {  
  40.             int v = edge[i].to;  
  41.             if (edge[i].cap > 0&&dep[v] == -1) //容量大于0&&未在dep中  
  42.             {  
  43.                 dep[v] = dep[u] + 1;        //建立层次图  
  44.                 que[rear ++] = v;  
  45.                 rear = rear % VM;  
  46.                 if (v == des)  //找到汇点 返回  
  47.                     return 1;  
  48.             }  
  49.         }  
  50.     }  
  51.     return 0;  
  52. }  
  53. int dinic (int src,int des)  
  54. {  
  55.     int i,res = 0,top;  
  56.     int stack[VM];    //stack为栈,存储当前增广路  
  57.     int cur[VM];        //存储当前点的后继 跟head是一样的  
  58.     while (BFS(src,des))   //if BFS找到增广路  
  59.     {  
  60.         memcpy (cur,head,sizeof (head));  
  61.         int u = src;       //u为当前结点  
  62.         top = 0;  
  63.         while (1)  
  64.         {  
  65.             if (u == des)     //增广路已全部进栈  
  66.             {  
  67.                 int min = inf,loc ;  
  68.                 for (i = 0;i < top;i ++)       //找最小的增广跟并loc记录其在stack中位置  
  69.                     if (min > edge[stack[i]].cap)  //以便退回该边继续DFS  
  70.                     {  
  71.                         min = edge[stack[i]].cap;  
  72.                         loc = i;  
  73.                     }  
  74.                 for (i = 0;i < top;i ++)   //偶数^1 相当加1 奇数^1相当减1 当正向边 = 0&&路径不合适时,正加负减  
  75.                 {                           //偶数是正向边,奇数是负向边,边从0开始  
  76.                     edge[stack[i]].cap -= min;  
  77.                     edge[stack[i]^1].cap += min;  
  78.                 }                              //将增广路中的所有边修改  
  79.                 res += min;  
  80.                 top = loc;  
  81.                 u = edge[stack[top]].frm;         //当前结点修改为最小边的起点  
  82.             }  
  83.             for (i = cur[u];i != -1;cur[u] = i = edge[i].next)   //找到当前结点对应的下一条边  
  84.                 if (edge[i].cap != 0&&dep[u] + 1 == dep[edge[i].to])//不满足条件时,修改cur值(去掉不合适的占)eg:1-->2 1-->3 1-->4 有边 但只有  
  85.                     break;                                  // 1-->4 这条边满足条件 就把1到2、3的边给去掉  
  86.             if (cur[u] != -1)            //当前结点的下一条边存在  
  87.             {  
  88.                 stack[top ++] = cur[u];   //把该边放入栈中  
  89.                 u = edge[cur[u]].to;         //再从下个点开始找  
  90.             }  
  91.             else  
  92.             {  
  93.                 if (top == 0)        //当前结点无未遍历的下一条边且栈空,DFS找不到下一条增广路  
  94.                     break;  
  95.                 dep[u] = -1;            //当前结点不在增广路中,剔除该点  
  96.                 u = edge[stack[--top]].frm; //退栈 回朔,继续查找  
  97.             }  
  98.         }  
  99.     }  
  100.     return res;  
  101. }  
  102. int main ()///坐标从0或1开始均可  注意别忘记下面的2个初始化  
  103. {  
  104.     int np,nc,m,v1,v2,w,n;  
  105.     int src,des;  
  106.     char str[20];  
  107.     while (scanf ("%d%d%d%d",&n,&np,&nc,&m)!=EOF)  
  108.     {  
  109.         ep = 0;//边的初始化  
  110.         src = n;  
  111.         des = n+1;  
  112.         memset (head,-1,sizeof(head));///这里初始化  
  113.         while (m --)  
  114.         {  
  115.             scanf ("%s",str);  
  116.             sscanf (str,"(%d,%d)%d",&v1,&v2,&w);  
  117.             addedge (v1,v2,w);  
  118.         }  
  119.         while (np --)  
  120.         {  
  121.             scanf ("%s",str);  
  122.             sscanf (str,"(%d)%d",&v2,&w);  
  123.             addedge (src,v2,w);  
  124.         }  
  125.         while (nc--)  
  126.         {  
  127.             scanf ("%s",str);  
  128.             sscanf (str,"(%d)%d",&v1,&w);  
  129.             addedge (v1,des,w);  
  130.         }  
  131.         int ans = dinic (src,des);  
  132.         printf ("%d\n",ans);  
  133.     }  
  134.     return 0;  
  135. }  



sap 算法  注意上面的n有用


[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. const int VM = 110, EM = 20500, inf = 0x3f3f3f3f;  
  4. struct Edge  
  5. {  
  6.     int to, frm, nxt, cap;  
  7. }edge[EM];  
  8.   
  9. int head[VM], ep, n, src, des;  
  10. int dep[VM], gap[VM]; //gap[x]=y:说明残留网络中dep[i]=x的个数为y  
  11.   
  12. void addedge(int u, int v, int c)  
  13. {  
  14.     edge[ep].frm = u;  
  15.     edge[ep].to = v;  
  16.     edge[ep].cap = c;  
  17.     edge[ep].nxt = head[u];  
  18.     head[u] = ep++;  
  19.     edge[ep].frm = v;  
  20.     edge[ep].to = u;  
  21.     edge[ep].cap = 0;  
  22.     edge[ep].nxt = head[v];  
  23.     head[v] = ep++;  
  24. }  
  25.   
  26. void BFS()  
  27. {  
  28.     memset(dep, -1, sizeof(dep));  
  29.     memset(gap, 0, sizeof(gap));  
  30.     gap[0] = 1;   //说明此时有1个dep[i] = 0  
  31.     int que[VM], front = 0, rear = 0;  
  32.     dep[des] = 0;  
  33.     que[rear++] = des;  
  34.     int u, v;  
  35.     while (front != rear)  
  36.     {  
  37.         u = que[front++];  
  38.         front = front%VM;  
  39.         for (int i=head[u]; i!=-1; i=edge[i].nxt)  
  40.         {  
  41.             v = edge[i].to;  
  42.             if (edge[i].cap != 0 || dep[v] != -1)  
  43.                 continue;  
  44.             que[rear++] = v;  
  45.             rear = rear % VM;  
  46.             ++gap[dep[v] = dep[u] + 1];  //求出各层次的数量  
  47.         }  
  48.     }  
  49. }  
  50.   
  51. int Sap()  
  52. {  
  53.     int res = 0;  
  54.     BFS();  
  55.     int cur[VM];  
  56.     int stack[VM], top = 0;  
  57.     memcpy(cur, head, sizeof(head));  
  58.     int u = src, i;  
  59.     while (dep[src] < n)  
  60.     {  
  61.         if (u == des)  
  62.         {  
  63.             int temp = inf, inser = n;  
  64.             for (i=0; i!=top; ++i)  
  65.                 if (temp > edge[stack[i]].cap)  
  66.                 {  
  67.                     temp = edge[stack[i]].cap;  
  68.                     inser = i;  
  69.                 }  
  70.             for (i=0; i!=top; ++i)  
  71.             {  
  72.                 edge[stack[i]].cap -= temp;  
  73.                 edge[stack[i]^1].cap += temp;  
  74.             }  
  75.             res += temp;  
  76.             top = inser;  
  77.             u = edge[stack[top]].frm;  
  78.         }  
  79.   
  80.         if (dep[u] != 0 && gap[dep[u] -1] == 0)//出现断层,无增广路  
  81.             break;  
  82.         for (i = cur[u]; i != -1; i = edge[i].nxt)//遍历与u相连的未遍历结点  
  83.             if (dep[edge[i].to] != -1)  
  84.                 if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1) //层序关系, 找到允许  
  85.                     break;  
  86.   
  87.         if (i != -1)//找到允许弧  
  88.         {  
  89.             cur[u] = i;  
  90.             stack[top++] = i;//加入路径栈  
  91.             u = edge[i].to;//查找下一个结点  
  92.         }  
  93.         else   //无允许的路径,修改标号 当前点的标号比与之相连的点中最小的多1  
  94.         {  
  95.             int min = n;  
  96.             for (i = head[u]; i != -1; i = edge[i].nxt) //找到与u相连的v中dep[v]最小的点  
  97.             {  
  98.                 if (edge[i].cap == 0)  
  99.                     continue;  
  100.                 if (min > dep[edge[i].to])  
  101.                 {  
  102.                     min = dep[edge[i].to];  
  103.                     cur[u] = i;          //最小标号就是最新的允许弧  
  104.                 }  
  105.             }  
  106.             --gap[dep[u]];          //dep[u] 的个数变化了 所以修改gap  
  107.             ++gap[dep[u] = min + 1]; //将dep[u]设为min(dep[v]) + 1, 同时修改相应的gap[]  
  108.             if (u != src) //该点非源点&&以u开始的允许弧不存在,退点  
  109.                 u = edge[stack[--top]].frm;  
  110.         }  
  111.     }  
  112.     return res;  
  113. }  
  114.   
  115. int main()///坐标从0开始  
  116. {  
  117.     int i, np, nc, m;  
  118.     char str[10];  
  119.     while (scanf("%d %d %d %d", &n, &np, &nc, &m) != EOF)  
  120.     {  
  121.         ep = 0;  
  122.         memset(head, -1, sizeof(head));  
  123.         int u, v, c;  
  124.         src = n, des = n + 1;  
  125.         n += 2;  
  126.         for (i=0; i!=m; ++i)  
  127.         {  
  128.             scanf("%stack", str);  
  129.             sscanf(str, "(%d,%d)%d", &u, &v, &c);  
  130.             addedge(u, v, c);  
  131.         }  
  132.         for (i=0; i!=np; ++i)  
  133.         {  
  134.             scanf("%stack", str);  
  135.             sscanf(str, "(%d)%d", &v, &c);  
  136.             addedge(src, v, c);  
  137.         }  
  138.         for (i=0; i!=nc; ++i)  
  139.         {  
  140.             scanf("%stack", str);  
  141.             sscanf(str, "(%d)%d", &u, &c);  
  142.             addedge(u, des, c);  
  143.         }  
  144.         printf("%d\n", Sap());  
  145.     }  
  146.     return 0;  
  147. }  



 

POJ 2455 网络流 基础题 二分+网络流 dicnic 以及 sap算法

分类: 网络流   367人阅读  评论(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


[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #define VM 222  
  4. #define EM 81111*2  
  5. #define inf 0x3f3f3f3f  
  6. struct Edge  
  7. {  
  8.     int frm,to,cap,next;  
  9. }edge[EM];  
  10.   
  11. int head[VM],dep[VM],ep,n;     //dep为点的层次  
  12. void addedge (int cu,int cv,int cw)  //第一条边下标必须为偶数  
  13. {  
  14.     edge[ep].frm = cu;  
  15.     edge[ep].to = cv;  
  16.     edge[ep].cap = cw;  
  17.     edge[ep].next = head[cu];  
  18.     head[cu] = ep;  
  19.     ep ++;  
  20.     edge[ep].frm = cv;  
  21.     edge[ep].to = cu;  
  22.     edge[ep].cap = cw;  
  23.     edge[ep].next = head[cv];  
  24.     head[cv] = ep;  
  25.     ep ++;  
  26. }  
  27.   
  28. int BFS (int src,int des)     //求出层次图  
  29. {  
  30.     int que[VM],i,front = 0,rear = 0;  
  31.     memset (dep,-1,sizeof(dep));  
  32.     que[rear++] = src;  
  33.     dep[src] = 0;  
  34.     while (front != rear)  
  35.     {  
  36.         int u = que[front++];  
  37.         front = front%VM;  
  38.         for (i = head[u];i != -1;i = edge[i].next)  
  39.         {  
  40.             int v = edge[i].to;  
  41.             if (edge[i].cap > 0&&dep[v] == -1) //容量大于0&&未在dep中  
  42.             {  
  43.                 dep[v] = dep[u] + 1;        //建立层次图  
  44.                 que[rear ++] = v;  
  45.                 rear = rear % VM;  
  46.                 if (v == des)  //找到汇点 返回  
  47.                     return 1;  
  48.             }  
  49.         }  
  50.     }  
  51.     return 0;  
  52. }  
  53. int dinic (int src,int des)  
  54. {  
  55.     int i,res = 0,top;  
  56.     int stack[VM];    //stack为栈,存储当前增广路  
  57.     int cur[VM];        //存储当前点的后继 跟head是一样的  
  58.     while (BFS(src,des))   //if BFS找到增广路  
  59.     {  
  60.         memcpy (cur,head,sizeof (head));  
  61.         int u = src;       //u为当前结点  
  62.         top = 0;  
  63.         while (1)  
  64.         {  
  65.             if (u == des)     //增广路已全部进栈  
  66.             {  
  67.                 int min = inf,loc ;  
  68.                 for (i = 0;i < top;i ++)       //找最小的增广跟并loc记录其在stack中位置  
  69.                     if (min > edge[stack[i]].cap)  //以便退回该边继续DFS  
  70.                     {  
  71.                         min = edge[stack[i]].cap;  
  72.                         loc = i;  
  73.                     }  
  74.                 for (i = 0;i < top;i ++)   //偶数^1 相当加1 奇数^1相当减1 当正向边 = 0&&路径不合适时,正加负减  
  75.                 {                           //偶数是正向边,奇数是负向边,边从0开始  
  76.                     edge[stack[i]].cap -= min;  
  77.                     edge[stack[i]^1].cap += min;  
  78.                 }                              //将增广路中的所有边修改  
  79.                 res += min;  
  80.                 top = loc;  
  81.                 u = edge[stack[top]].frm;         //当前结点修改为最小边的起点  
  82.             }  
  83.             for (i = cur[u];i != -1;cur[u] = i = edge[i].next)   //找到当前结点对应的下一条边  
  84.                 if (edge[i].cap != 0&&dep[u] + 1 == dep[edge[i].to])//不满足条件时,修改cur值(去掉不合适的占)eg:1-->2 1-->3 1-->4 有边 但只有  
  85.                     break;                                  // 1-->4 这条边满足条件 就把1到2、3的边给去掉  
  86.             if (cur[u] != -1)            //当前结点的下一条边存在  
  87.             {  
  88.                 stack[top ++] = cur[u];   //把该边放入栈中  
  89.                 u = edge[cur[u]].to;         //再从下个点开始找  
  90.             }  
  91.             else  
  92.             {  
  93.                 if (top == 0)        //当前结点无未遍历的下一条边且栈空,DFS找不到下一条增广路  
  94.                     break;  
  95.                 dep[u] = -1;            //当前结点不在增广路中,剔除该点  
  96.                 u = edge[stack[--top]].frm; //退栈 回朔,继续查找  
  97.             }  
  98.         }  
  99.     }  
  100.     return res;  
  101. }  
  102. struct IN  
  103. {  
  104.     int x,y,c;  
  105. }q[EM];  
  106. int sovle(int mid,int src,int des,int m,int k)  
  107. {  
  108.     ep = 0;  
  109.     memset (head,-1,sizeof(head));  
  110.     for(int i=0;i<m;i++)  
  111.     {  
  112.        if(q[i].c<=mid)  
  113.         addedge(q[i].x,q[i].y,1);  
  114.        // addedge(q[i].y,q[i].x,1);  
  115.   
  116.     }  
  117.      if(dinic (src,des)>=k) return 1;  
  118.      return 0;  
  119. }  
  120. int main ()  
  121. {  
  122.     int n,m,v1,v2,w,k,i;  
  123.     int src,des;  
  124.     while (scanf ("%d %d %d",&n,&m,&k)!=EOF)  
  125.     {  
  126.        // ep = 0;  
  127.         src=1;des=n;  
  128.        // memset (head,-1,sizeof(head));  
  129.         for(i=0;i<m;i++)  
  130.         {  
  131.             scanf("%d %d %d",&v1,&v2,&w);  
  132.             q[i].x=v1;q[i].y=v2;q[i].c=w;  
  133.         }  
  134.         int left,right,mid,ans=-1;  
  135.         left=0;right=1000000;  
  136.         while(left<=right)  
  137.         {  
  138.             mid=(left+right)/2;  
  139.             if(sovle(mid,src,des,m,k))  
  140.             {  
  141.                 ans=mid;  
  142.                 right=mid-1;  
  143.             }  
  144.             else left=mid+1;  
  145.         }  
  146.         printf ("%d\n",ans);  
  147.     }  
  148.     return 0;  
  149. }  



Sap 算法

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #define VM 222  
  4. #define EM 81111*2  
  5. #define inf 0x3f3f3f3f  
  6.   
  7.   
  8. struct Edge  
  9. {  
  10.     int to, frm, nxt, cap;  
  11. }edge[EM];  
  12.   
  13. int head[VM], ep, n, src, des;  
  14. int dep[VM], gap[VM]; //gap[x]=y:说明残留网络中dep[i]=x的个数为y  
  15.   
  16. void addedge(int u, int v, int c)  
  17. {  
  18.     edge[ep].frm = u;  
  19.     edge[ep].to = v;  
  20.     edge[ep].cap = c;  
  21.     edge[ep].nxt = head[u];  
  22.     head[u] = ep++;  
  23.     edge[ep].frm = v;  
  24.     edge[ep].to = u;  
  25.     edge[ep].cap = 0;  
  26.     edge[ep].nxt = head[v];  
  27.     head[v] = ep++;  
  28. }  
  29.   
  30. void BFS()  
  31. {  
  32.     memset(dep, -1, sizeof(dep));  
  33.     memset(gap, 0, sizeof(gap));  
  34.     gap[0] = 1;   //说明此时有1个dep[i] = 0  
  35.     int que[VM], front = 0, rear = 0;  
  36.     dep[des] = 0;  
  37.     que[rear++] = des;  
  38.     int u, v;  
  39.     while (front != rear)  
  40.     {  
  41.         u = que[front++];  
  42.         front = front%VM;  
  43.         for (int i=head[u]; i!=-1; i=edge[i].nxt)  
  44.         {  
  45.             v = edge[i].to;  
  46.             if (edge[i].cap != 0 || dep[v] != -1)  
  47.                 continue;  
  48.             que[rear++] = v;  
  49.             rear = rear % VM;  
  50.             ++gap[dep[v] = dep[u] + 1];  //求出各层次的数量  
  51.         }  
  52.     }  
  53. }  
  54.   
  55. int Sap()  
  56. {  
  57.     int res = 0;  
  58.     BFS();  
  59.     int cur[VM];  
  60.     int stack[VM], top = 0;  
  61.     memcpy(cur, head, sizeof(head));  
  62.     int u = src, i;  
  63.     while (dep[src] < n)  
  64.     {  
  65.         if (u == des)  
  66.         {  
  67.             int temp = inf, inser = n;  
  68.             for (i=0; i!=top; ++i)  
  69.                 if (temp > edge[stack[i]].cap)  
  70.                 {  
  71.                     temp = edge[stack[i]].cap;  
  72.                     inser = i;  
  73.                 }  
  74.             for (i=0; i!=top; ++i)  
  75.             {  
  76.                 edge[stack[i]].cap -= temp;  
  77.                 edge[stack[i]^1].cap += temp;  
  78.             }  
  79.             res += temp;  
  80.             top = inser;  
  81.             u = edge[stack[top]].frm;  
  82.         }  
  83.   
  84.         if (dep[u] != 0 && gap[dep[u] -1] == 0)//出现断层,无增广路  
  85.             break;  
  86.         for (i = cur[u]; i != -1; i = edge[i].nxt)//遍历与u相连的未遍历结点  
  87.             if (dep[edge[i].to] != -1)  
  88.                 if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1) //层序关系, 找到允许  
  89.                     break;  
  90.   
  91.         if (i != -1)//找到允许弧  
  92.         {  
  93.             cur[u] = i;  
  94.             stack[top++] = i;//加入路径栈  
  95.             u = edge[i].to;//查找下一个结点  
  96.         }  
  97.         else   //无允许的路径,修改标号 当前点的标号比与之相连的点中最小的多1  
  98.         {  
  99.             int min = n;  
  100.             for (i = head[u]; i != -1; i = edge[i].nxt) //找到与u相连的v中dep[v]最小的点  
  101.             {  
  102.                 if (edge[i].cap == 0)  
  103.                     continue;  
  104.                 if (min > dep[edge[i].to])  
  105.                 {  
  106.                     min = dep[edge[i].to];  
  107.                     cur[u] = i;          //最小标号就是最新的允许弧  
  108.                 }  
  109.             }  
  110.             --gap[dep[u]];          //dep[u] 的个数变化了 所以修改gap  
  111.             ++gap[dep[u] = min + 1]; //将dep[u]设为min(dep[v]) + 1, 同时修改相应的gap[]  
  112.             if (u != src) //该点非源点&&以u开始的允许弧不存在,退点  
  113.                 u = edge[stack[--top]].frm;  
  114.         }  
  115.     }  
  116.     return res;  
  117. }  
  118.   
  119.   
  120.   
  121.   
  122. struct IN  
  123. {  
  124.     int x,y,c;  
  125. }q[EM];  
  126. int sovle(int mid,int m,int k)  
  127. {  
  128.     //printf("jin\n");  
  129.     ep = 0;  
  130.     memset (head,-1,sizeof(head));  
  131.     for(int i=0;i<m;i++)  
  132.     {  
  133.        if(q[i].c<=mid)  
  134.          {  
  135.              addedge(q[i].x,q[i].y,1);  
  136.              addedge(q[i].y,q[i].x,1);//不知道为什么 sap需要添加2次 相反边    
  137.          }  
  138.     }  
  139.      if(Sap()>=k) return 1;  
  140.      return 0;  
  141. }  
  142. int main ()  
  143. {  
  144.     int m,v1,v2,w,k,i;  
  145.     while (scanf ("%d %d %d",&n,&m,&k)!=EOF)  
  146.     {  
  147.         src=1;des=n;  
  148.         for(i=0;i<m;i++)  
  149.         {  
  150.             scanf("%d %d %d",&v1,&v2,&w);  
  151.             q[i].x=v1;q[i].y=v2;q[i].c=w;  
  152.         }  
  153.         int left,right,mid,ans=-1;  
  154.         left=0;right=1000000;  
  155.         while(left<=right)  
  156.         {  
  157.             mid=(left+right)/2;  
  158.             if(sovle(mid,m,k))  
  159.             {  
  160.                 ans=mid;  
  161.                 right=mid-1;  
  162.             }  
  163.             else left=mid+1;  
  164.         }  
  165.         printf ("%d\n",ans);  
  166.     }  
  167.     return 0;  
  168. }  



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值