zoukankan      html  css  js  c++  java
  • 网络(最大)流初步+二分图初步 (浅谈EK,Dinic, Hungarian method:]

    本文中  N为点数,M为边数;

    EK: (brute_force) ;

    每次bfs暴力找到一条增广路,更新流量,代码如下 :

    时间复杂度:O(NM²);

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3  
     4 struct node{
     5     int next,to,len;
     6 }edge[200005];
     7 
     8 int val[10005],head[200005],vis[10005],from[100005];
     9 int n,m,s,t,ans,inf=2147483647,cnt=1;
    10 
    11 inline void add_edge(int u,int v,int len){
    12     edge[++cnt].to=v;
    13     edge[cnt].next=head[u];
    14     edge[cnt].len=len;
    15     head[u]=cnt;
    16 }
    17 
    18 inline bool bfs(){
    19     queue <int> q;
    20     memset(vis,0,sizeof(vis));
    21     val[s]=inf;
    22     q.push(s);vis[s]=1;
    23     while(q.size()){
    24         int u=q.front(); q.pop();
    25         for(int i=head[u];i;i=edge[i].next){
    26             int v=edge[i].to;
    27             if(vis[v]||!edge[i].len)continue;
    28             vis[v]=1; q.push(v);
    29             from[v]=i;
    30             val[v]=min(val[u],edge[i].len); 
    31             if(v==t)return true;
    32         }
    33     }
    34     return false;
    35 }
    36 
    37 inline void update(){
    38     int u=t;
    39     while(u!=s){
    40         int p=from[u];
    41         edge[p].len-=val[t];
    42         edge[p^1].len+=val[t];
    43         u=edge[p^1].to;
    44     }
    45     ans+=val[t];
    46 }
    47 
    48 int main(){
    49     int x,y,z;
    50     scanf("%d %d %d %d",&n,&m,&s,&t);
    51     for(int i=1;i<=m;i++){
    52         scanf("%d %d %d",&x,&y,&z);
    53         add_edge(x,y,z);
    54         add_edge(y,x,0); 
    55     }
    56     while(bfs())update();
    57     printf("%d
    ",ans);
    58     return 0;
    59 }
    View Code

    Dinic: 显然,EK算法每次只bfs找到一条增广路径是非常睿智低效的,Dinic算法就是通过dfs 每次找到一张增广网,从而使增广速度加快;

    p.s. 当前弧优化:在dfs进行增广时,有些边已经对此次的增广做出了全部的贡献(换言之,他在当前的残量网络中已经没有贡献了),所以就不必再考虑它;

    代码如下:

    时间复杂度:O(Dinic(N, M))    O(N*M½) ~ O(M*N²);

      1 //15owzLy1
      2 //Dinic.cpp
      3 //2018 10 10      11:51:55
      4 #include <iostream>
      5 #include <cstdio>
      6 #include <cstring>
      7 #include <cmath>
      8 #include <algorithm>
      9 #include <queue>
     10 #include <vector>
     11 #include <map>
     12 #include <set>
     13 #define lson tl, mid, rt<<1
     14 #define rson mid+1, tr, rt<<1|1
     15 #define pb(__) push_back(__)
     16 #define fr() front()
     17 #define bg() begin()
     18 #define it iterator
     19 #define INF 2100000000
     20 typedef long long ll;
     21 typedef double db;
     22 
     23 const int N = 10005, M = 100005;
     24 
     25 //edge begin
     26 struct node {
     27     int next, to, len;
     28 }edge[M<<1];
     29 int head[N], cnt=1;
     30 //edge end
     31 int n, m, s, t;
     32 
     33 template<typename T>inline void read(T &_) {
     34     _=0;bool __=0;char ___=getchar();
     35     while(___<'0'||___>'9'){__|=(___=='-');___=getchar();}
     36     while(___>='0'&&___<='9'){_=(_<<1)+(_<<3)+(___^48);___=getchar();}
     37     _=__?-_:_;
     38 }
     39 
     40 template<class T>inline void get_max(T &_, T __) { _=_>__?_:__; }
     41 template<class T>inline void get_min(T &_, T __) { _=_<__?_:__; }
     42 template<class T>inline void Swap(T &_, T &__) { T ___=_;_=__;__=___; }
     43 template<class T>inline T abs(T _) { return _>0?_:-_; }
     44 
     45 inline void jb(int u, int v, int w) {
     46     edge[++cnt].to=v;
     47     edge[cnt].next=head[u];
     48     edge[cnt].len=w;
     49     head[u]=cnt;
     50 }
     51 
     52 namespace Dinic {
     53     int l, r, q[N], cur[N], dep[N], Max_flow;
     54     inline bool bfs() {
     55         memset(dep, 0, sizeof(dep));
     56         memcpy(cur, head, sizeof(head));
     57         l=r=0; q[++r]=s; dep[s]=1;
     58         while(l<r) {
     59             int u=q[++l];
     60             for(int i=head[u];i;i=edge[i].next) {
     61                 int v=edge[i].to, w=edge[i].len;
     62                 if(dep[v]==0&&w) dep[v]=dep[u]+1, q[++r]=v;
     63             }
     64         }
     65         if(dep[t]) return true;
     66         else       return false;
     67     }
     68     int dfs(int u, int min) {
     69         if(min==0||u==t) return min;
     70         int flow=0, f;
     71         for(int &i=cur[u];i;i=edge[i].next) {
     72             int v=edge[i].to, w=edge[i].len;
     73             if(dep[v]==dep[u]+1&&(f=dfs(v, std::min(min, w)))) {
     74                 flow+=f; min-=f;
     75                 edge[i].len-=f;
     76                 edge[i^1].len+=f;
     77             }
     78         }
     79         return flow;
     80     }
     81     inline void Dinic() {
     82         int flow;
     83         while(bfs())
     84             while(flow=dfs(s, INF)) Max_flow+=flow;
     85         printf("%d
    ", Max_flow);
     86     }
     87 }
     88 
     89 int main() {
     90 #ifndef ONLINE_JUDGE
     91     freopen("Dinic.in","r",stdin);
     92     freopen("Dinic.out","w",stdout);
     93 #endif
     94     int x, y, z;
     95     read(n), read(m), read(s), read(t);
     96     for(int i=1;i<=m;i++) {
     97         read(x), read(y), read(z);
     98         jb(x, y, z), jb(y, x, 0);
     99     }
    100     Dinic::Dinic();    
    101     return 0;
    102 }
    View Code

    二分图:顾名思义,就是可以分成两个部分的图(把点分成两边,同一侧的点只能向另一侧的点连边);

    二分图最大匹配:在边中选一个子集,使得每个点最多与该边集中的一个点相连,边数最多的子集即最大匹配;

    如何求???

    1.匈牙利算法(Hungarian method) : (brute_force) ———— 看代码

    将点分为两部分(左右两边);(u在左边,v在右边)

    mat[v]=u表示当前与v匹配的点为u;

    每次dfs即寻求增广路;

     1 //15owzLy1
     2 //Hungary.cpp
     3 //2018 10 10      17:04:04
     4 #include <iostream>
     5 #include <cstdio>
     6 #include <cstring>
     7 #include <cmath>
     8 #include <algorithm>
     9 #include <queue>
    10 #include <vector>
    11 #include <map>
    12 #include <set>
    13 #define lson tl, mid, rt<<1
    14 #define rson mid+1, tr, rt<<1|1
    15 #define pb(__) push_back(__)
    16 #define fr() front()
    17 #define bg() begin()
    18 #define it iterator
    19 #define INF 2100000000
    20 typedef long long ll;
    21 typedef double db;
    22 
    23 const int N = 1005, M = 1005;
    24 //edge bg;
    25 struct node {
    26     int next, to;
    27 }edge[M*N];
    28 int head[N], cnt=1;
    29 //edge end;
    30 int mat[N], n, m, e;
    31 bool vis[N];
    32 
    33 template<typename T>inline void read(T &_) {
    34     _=0;bool __=0;char ___=getchar();
    35     while(___<'0'||___>'9'){__|=(___=='-');___=getchar();}
    36     while(___>='0'&&___<='9'){_=(_<<1)+(_<<3)+(___^48);___=getchar();}
    37     _=__?-_:_;
    38 }
    39 
    40 template<class T>inline void get_max(T &_, T __) { _=_>__?_:__; }
    41 template<class T>inline void get_min(T &_, T __) { _=_<__?_:__; }
    42 template<class T>inline void Swap(T &_, T &__) { T ___=_;_=__;__=___; }
    43 template<class T>inline T abs(T _) { return _>0?_:-_; }
    44 
    45 inline void jb(int u, int v) {
    46     edge[++cnt].to=v;
    47     edge[cnt].next=head[u];
    48     head[u]=cnt;
    49 }
    50 
    51 bool dfs(int u) {
    52     vis[u]=true;
    53     for(int i=head[u];i;i=edge[i].next) {
    54         int v=edge[i].to;
    55         if(vis[mat[v]]) continue;
    56         if(mat[v]==0||dfs(mat[v])) {
    57             mat[v]=u; return true;
    58         }
    59     }
    60     return false;
    61 }
    62 
    63 inline int Hungary() {
    64     int res=0;
    65     for(int i=1;i<=n;i++) {
    66         memset(vis, false, sizeof(vis));
    67         if(dfs(i)) res++;
    68     }
    69     return res;
    70 }
    71 
    72 int main() {
    73 #ifndef ONLINE_JUDGE
    74     freopen("Hungary.in","r",stdin);
    75     freopen("Hungary.out","w",stdout);
    76 #endif
    77     int x, y;
    78     read(n), read(m), read(e);//n, m为左右两边点的个数,e为边数
    79     while(e--) {
    80         read(x), read(y);
    81         if(y>m) continue;
    82         jb(x, y);
    83     }
    84     printf("%d
    ", Hungary());
    85     return 0;
    86 }
    View Code

    2.与网络流有何关系????

    将源点和左边的点相连,右边的点与汇点相连,流量设为1;

    左右点之间的边流量设为一个大于等于1的整数;

    此时求出最大流,即为最大匹配;

    感性理解一下:最大匹配是在边集中选出一个子集;一个点与该子集中的边相连,与该点与源点或者汇点所连边的流量流满是等效的;

    建边过程:

     1 inline void jb(int u, int v, int w) {
     2     edge[++cnt].to=v;
     3     edge[cnt].next=head[u];
     4     edge[cnt].len=w;
     5     head[u]=cnt;
     6 }
     7 int main() {
     8     int x, y, z;
     9     read(n), read(m), read(s), read(t);
    10     for(int i=1;i<=m;i++) {
    11         read(x), read(y), read(z);
    12         jb(x, y, z), jb(y, x, 0);
    13     }
    14     Dinic::Dinic();    
    15     return 0;
    16 }
    View Code
  • 相关阅读:
    杭电 FatMouse' Trade
    Navicat Report Viewer 设置选项的问题
    用Beyond Compare精确查找文本内容的方法
    Beyond Compare表格比较详解
    Navicat Report Viewer 如何连接到 MySQL 数据库
    Navicat for MySQL 选项设置技巧详解
    Navicat 用什么方法检测 Oracle 数据库安全性
    有哪些好用的比较工具
    Beyond Compare文件比较有哪些方式
    Beyond Compare怎样修改差异文件夹
  • 原文地址:https://www.cnblogs.com/15owzLy1-yiylcy/p/9799901.html
Copyright © 2011-2022 走看看