zoukankan      html  css  js  c++  java
  • 常用的最大流算法 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 }
  • 相关阅读:
    383. Ransom Note
    598. Range Addition II
    453. Minimum Moves to Equal Array Elements
    492. Construct the Rectangle
    171. Excel Sheet Column Number
    697. Degree of an Array
    665. Nondecreasing Array
    视频网站使用H265编码能提高视频清晰度吗?
    现阶段的语音视频通话SDK需要解决哪些问题?
    企业远程高清会议平台视频会议系统在手机端使用的必备要求有哪些?
  • 原文地址:https://www.cnblogs.com/pupil-xj/p/11831860.html
Copyright © 2011-2022 走看看