• 【板子】网络流


    最大流:

    例题: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
    ", 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
    ",ans);
    142     }
    143     return 0;
    144 }
  • 相关阅读:
    一款JS+CSS实现的无缝平滑图片滚动代码
    2个按钮控制的左右图片滚动特效代码
    JS+CSS控制左右切换鼠标可控的无缝图片滚动代码
    用CSS实现图片水印效果代码
    用鼠标拖动图片的JS代码
    一款实用的JavaScript图片幻灯片代码
    摘自搜狐女人频道的图片切换的JS代码
    JS防PS里的图片拖拉缩放效果代码
    鼠标移至图片后抖动的JS代码
    WINDOWS补丁的多线程下载方法和安装技巧
  • 原文地址:https://www.cnblogs.com/Asumi/p/9751117.html
Copyright © 2020-2023  润新知