• 常用的最大流算法 Dinic 和 最小费用最大流SPFA写法


    // Dinic 是EK的优化 (都是FF思想)

    //附带EK算法O(V*E2):

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<queue>
     4 #define INF 0x3f3f3f3f
     5 using namespace std;
     6 
     7 inline int read() {
     8     char c=getchar();int x=0,f=1;
     9     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    10     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    11     return x*f;
    12 }
    13 
    14 const int MAXN = 10000+5;
    15 const int MAXE = 100000*2+5;
    16 
    17 int num;
    18 int head[MAXN];
    19 struct node {
    20     int u, v, flow;
    21     int next;
    22 } edge[MAXE];
    23 
    24 inline void add(int x, int y, int w) {
    25     edge[num].u = x;
    26     edge[num].v = y;
    27     edge[num].flow = w;
    28     edge[num].next = head[x];
    29     head[x] = num++;
    30 }
    31 
    32 int n, m, s, e;
    33 int path[MAXN], A[MAXN];
    34 
    35 int EK() {
    36     int ans = 0;
    37     while(1) {
    38         for(int i = 1; i <= n; ++i) A[i] = 0;
    39         queue<int> q;
    40         q.push(s);
    41         A[s] = INF;
    42         while(!q.empty()) {
    43             int u = q.front();
    44             q.pop();
    45             for(int i = head[u]; i != -1; i = edge[i].next) {
    46                 int v = edge[i].v;
    47                 if(!A[v] && edge[i].flow) {
    48                     path[v] = i;
    49                     A[v] = min(A[u], edge[i].flow);
    50                     q.push(v);
    51                 }
    52             }
    53             if(A[e]) break;
    54         }
    55         if(!A[e]) break;
    56         for(int i = e; i != s; i = edge[path[i]].u) {
    57             edge[path[i]].flow -= A[e];
    58             edge[path[i]^1].flow += A[e];
    59         }
    60         ans += A[e];
    61     }
    62     return ans;
    63 }
    64 
    65 int main() {
    66     n = read(); m = read(); s = read(); e = read();
    67     num = 0;
    68     for(int i = 1; i <= n; ++i) head[i] = -1;
    69     for(int i = 0; i != m; ++i) {
    70         int x = read(), y = read(), w = read();
    71         add(x, y, w);
    72         add(y, x, 0);
    73     }
    74     printf("%d
    ", EK());
    75     return 0;
    76 }
    View Code

    Dinic 参考博客 点我.

    Dinic 的三种优化: 当前弧优化、多路增广、炸点 。上面的博客讲的很清楚

    代码:

      1 /*
      2  * @Promlem: 
      3  * @Time Limit: ms
      4  * @Memory Limit: k
      5  * @Author: pupil-XJ
      6  * @Date: 2019-11-10 19:34:37
      7  * @LastEditTime: 2019-11-10 20:56:40
      8  */
      9 #include<cstdio>
     10 #include<algorithm>
     11 #include<queue>
     12 #define INF 0x3f3f3f3f
     13 using namespace std;
     14 
     15 inline int read() {
     16     char c=getchar();int x=0,f=1;
     17     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
     18     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     19     return x*f;
     20 }
     21 
     22 const int MAXN = 200+5;
     23 const int MAXE = 200*2+5;
     24 
     25 int num;
     26 int head[MAXN];
     27 struct node {
     28     int v, flow;
     29     int next;
     30 } edge[MAXN];
     31 
     32 inline void add(int x, int y, int w) {
     33     edge[num].v = y;
     34     edge[num].flow = w;
     35     edge[num].next = head[x];
     36     head[x] = num++;
     37 }
     38 
     39 int n, m, s, e;
     40 int cur[MAXN], dis[MAXN];
     41 
     42 bool bfs() {
     43     for(int i = 1; i <= n; ++i) dis[i] = 0;
     44     dis[s] = 1;
     45     queue<int> q;
     46     q.push(s);
     47     while(!q.empty()) {
     48         int u = q.front(); if(u == e) return true;
     49         q.pop();
     50         for(int i = head[u]; i != -1; i = edge[i].next) {
     51             int v = edge[i].v;
     52             if(!dis[v] && edge[i].flow) {
     53                 dis[v] = dis[u] + 1;
     54                 q.push(v);
     55             }
     56         }
     57     }
     58     return dis[e] != 0;
     59 }
     60 
     61 int dfs(int u, int f) { //当前节点,到目前为止可增加流量。返回可增加流量
     62     if(u == e || (!f)) return f; // 到达汇点 || 已无残量
     63     int flow = 0;
     64     for(int& i = cur[u]; i != -1; i = edge[i].next) {// '&'目的 -> 当前弧优化
     65         int v = edge[i].v;
     66         if(dis[v] == dis[u] + 1) {
     67             int di = dfs(v, min(f, edge[i].flow));
     68             if(di > 0) {
     69                 flow += di;//这里不急着return,而是记录一下这条链上能增广的流量,再接着找下一条链
     70                 f -= di;//把从u开始能增广的容量相应减去
     71                 edge[i].flow -= di;
     72                 edge[i^1].flow += di;
     73                 if(!f) break;// 没容量了
     74             }
     75         }
     76     }
     77     if(!flow) dis[u] = -1;//这个点甚至没有增广出一点流量,炸掉它
     78     return flow;
     79 }
     80 
     81 int Dinic() {
     82     int ans = 0;
     83     while(bfs()) {
     84         for(int i = 1; i <= n; ++i) cur[i] = head[i];
     85         ans += dfs(s, INF);
     86     }
     87     return ans;
     88 }
     89 
     90 int main() {
     91     n = read(); m = read(); s = read(); e = read();
     92     num = 0;
     93     for(int i = 1; i <= n; ++i) head[i] = -1;
     94     for(int i = 0; i != m; ++i) {
     95         int x = read(), y = read(), w = read();
     96         add(x, y, w);
     97         add(y, x, 0);
     98     }
     99     printf("%d
    ", Dinic());
    100     return 0;
    101 }

     // 费用流 定义: 百度百科

    // 例题 poj 2516

      1 /*
      2  * @Promlem: 
      3  * @Time Limit: ms
      4  * @Memory Limit: k
      5  * @Author: pupil-XJ
      6  * @Date: 2019-11-11 22:37:28
      7  * @LastEditTime: 2019-11-12 11:13:39
      8  */
      9 #include<cstdio>
     10 #include<ctime>
     11 #include<algorithm>
     12 #include<stack>
     13 #include<map>
     14 using namespace std;
     15 const int INF = 0x3f3f3f3f;
     16 typedef pair<int,int> Pair;
     17 const int MAXN = 800+5;
     18 const int MAXE = 102000+5;
     19 
     20 int num;
     21 int head[MAXN];
     22 struct node {
     23     int v, flow, dis;
     24     int next;
     25 } edge[MAXE];
     26 
     27 inline void add(int x, int y, int w, int d) {
     28     edge[num].v = y;
     29     edge[num].flow = w;
     30     edge[num].dis = d;
     31     edge[num].next = head[x];
     32     head[x] = num++;
     33 }
     34 
     35 int n, m, k, sum;
     36 int S, T;
     37 
     38 int maxflow, mincost;
     39 int flow[MAXN], dis[MAXN];
     40 int pre[MAXN], last[MAXN];
     41 bool vis[MAXN];
     42 
     43 bool spfa() {
     44     for(int i = 1; i <= T; ++i) flow[i] = dis[i] = INF, vis[i] = false;
     45     dis[S] = 0;
     46     vis[S] = true;
     47     pre[T] = -1;
     48     stack<int> q;
     49     q.push(S);
     50     while(!q.empty()) {
     51         int u = q.top();
     52         q.pop();
     53         vis[u] = false;
     54         for(int i = head[u]; i != -1; i = edge[i].next) {
     55             int v = edge[i].v;
     56             if(edge[i].flow && dis[v] > dis[u] + edge[i].dis) {
     57                 dis[v] = dis[u] + edge[i].dis;
     58                 pre[v] = u;
     59                 last[v] = i;
     60                 flow[v] = min(flow[u], edge[i].flow);
     61                 if(!vis[v]) {
     62                     vis[v] = true;
     63                     q.push(v);
     64                 }
     65             }
     66         }
     67     }
     68     return  pre[T] != -1;
     69 }
     70 
     71 bool MCMF() {
     72     maxflow = mincost = 0;
     73     while(spfa()) {
     74         maxflow += flow[T];
     75         mincost += flow[T]*dis[T];
     76         int u = T;
     77         while(u != S) {
     78             edge[last[u]].flow -= flow[T];
     79             edge[last[u]^1].flow += flow[T];
     80             u = pre[u];
     81         }
     82     }
     83     return maxflow == sum;
     84 }
     85 
     86 int need[155][155], have[155][155], cost[155][155][155];
     87 
     88 void draw(int k_num) {
     89     S = 1; T = 2+m+n;
     90     num = sum = 0;
     91     for(int i = 1; i <= T; ++i) head[i] = -1;
     92     for(int i = 2; i <= 1+m; ++i) {
     93         add(S, i, have[i-1][k_num], 0);
     94         add(i, S, 0, 0);
     95     }
     96     for(int i = 2; i <= 1+m; ++i) {
     97         for(int j = 2+m; j <= 1+m+n; ++j) {
     98             add(i, j, INF, cost[j-1-m][i-1][k_num]);
     99             add(j, i, 0, -cost[j-1-m][i-1][k_num]);
    100         }
    101     }
    102     for(int i = 2+m; i <= 1+m+n; ++i) {
    103         add(i, T, need[i-1-m][k_num], 0);
    104         add(T, i, 0, 0);
    105         sum += need[i-1-m][k_num];
    106     }
    107 }
    108 
    109 int solve() {
    110     int ans = 0;
    111     for(int i = 1; i <= k; ++i) {
    112         draw(i);
    113         if(MCMF()) ans += mincost;
    114         else return -1;
    115     }
    116     return ans;
    117 }
    118 
    119 void input() {
    120     int x;
    121     for(int i = 1; i <= n; ++i) {
    122         for(int j = 1; j <= k; ++j) {
    123             scanf("%d", &x);
    124             need[i][j] = x;
    125         }
    126     }
    127     for(int i = 1; i <= m; ++i) {
    128         for(int j = 1; j <= k; ++j) {
    129             scanf("%d", &x);
    130             have[i][j] = x;
    131         }
    132     }
    133     for(int i = 1; i <= k; ++i) {
    134         for(int u = 1; u <= n; ++u) {
    135             for(int v = 1; v <= m; ++v) {
    136                 scanf("%d", &x);
    137                 cost[u][v][i] = x;
    138             }
    139         }
    140     }
    141 }
    142 
    143 int main() {
    144     while(1) {
    145         scanf("%d%d%d", &n, &m, &k);
    146         if(!n) break;
    147         input();
    148         printf("%d
    ", solve());
    149     }
    150     return 0;
    151 }
    View Code

    SPFA写法--在每次找增广路的时候选择找一条到汇点费用之和最小的链 然后 ans += 当前找到的最短路*每次的增广量

    (dijkstra不会。。。)

      1 /*
      2  * @Promlem: 
      3  * @Time Limit: ms
      4  * @Memory Limit: k
      5  * @Author: pupil-XJ
      6  * @Date: 2019-11-11 19:02:37
      7  * @LastEditTime: 2019-11-11 19:20:27
      8  */
      9 
     10 #include<cstdio>
     11 #include<algorithm>
     12 #include<queue>
     13 #define INF 0x3f3f3f3f
     14 using namespace std;
     15 
     16 inline int read() {
     17     char c=getchar();int x=0,f=1;
     18     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
     19     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     20     return x*f;
     21 }
     22 
     23 const int MAXN = 200+5;
     24 const int MAXE = 200*2+5;
     25 
     26 int num;
     27 int head[MAXN];
     28 struct node {
     29     int v, flow, dis;
     30     int next;
     31 } edge[MAXN];
     32 
     33 inline void add(int x, int y, int w, int dis) {
     34     edge[num].v = y;
     35     edge[num].flow = w;
     36     edge[num].dis = dis;
     37     edge[num].next = head[x];
     38     head[x] = num++;
     39 }
     40 
     41 int n, m, s, e;
     42 int maxflow, mincost;
     43 int flow[MAXN], dis[MAXN];
     44 int pre[MAXN], last[MAXN];
     45 bool vis[MAXN];
     46 
     47 bool spfa() {
     48     for(int i = 1; i <= n; ++i) flow[i] = dis[i] = INF, vis[i] = false;
     49     vis[s] = true;
     50     dis[s] = 0; pre[e] = -1;
     51     queue<int> q;
     52     q.push(s);
     53     while(!q.empty()) {
     54         int u = q.front();
     55         q.pop();
     56         vis[u] = false;
     57         for(int i = head[u]; i != -1; i = edge[i].next) {
     58             int v = edge[i].v;
     59             if(edge[i].flow && dis[v] > dis[u] + edge[i].dis) {
     60                 dis[v] = dis[u] + edge[i].dis;
     61                 pre[v] = u;
     62                 last[v] = i;
     63                 flow[v] = min(flow[u], edge[i].flow);
     64                 if(!vis[v]) {
     65                     vis[v] = true;
     66                     q.push(v);
     67                 }
     68             }
     69         }
     70     }
     71     return pre[e] != -1;
     72 }
     73 
     74 void MCMF() {
     75     maxflow = mincost = 0;
     76     while(spfa()) {
     77         int u = e;
     78         maxflow += flow[u];
     79         mincost += flow[u]*dis[u];
     80         while(u != s) {
     81             edge[last[u]].flow -= flow[e];
     82             edge[last[u]^1].flow += flow[e];
     83             u = pre[u];
     84         }
     85     }
     86 }
     87 
     88 int main() {
     89     n = read(); m = read(); s = read(); e = read();
     90     num = 0;
     91     for(int i = 1; i <= n; ++i) head[i] = -1;
     92     for(int i = 0; i != m; ++i) {
     93         int x = read(), y = read(), w = read(), f = read();
     94         add(x, y, w, f);
     95         add(y, x, 0,-f);
     96     }
     97     MCMF();
     98     printf("%d %d
    ", maxflow, mincost);
     99     return 0;
    100 }
  • 相关阅读:
    Hexo Daemon
    Eclipse远程Debug
    IT人都欠自已一个Lable Page
    Linux下java/bin目录下的命令集合
    python笔记--5--文件操作
    python笔记--4--面向对象
    python笔记--3--函数、生成器、装饰器、函数嵌套定义、函数柯里化
    python笔记--1--基础知识、数据类型
    Django笔记--视图
    C++笔记--1
  • 原文地址:https://www.cnblogs.com/pupil-xj/p/11831860.html
Copyright © 2020-2023  润新知