zoukankan      html  css  js  c++  java
  • 网络流之Dinic算法

    初学网络流。存一下Dinic板子。

    复杂度O(n^2*m)

    UVA - 1515 Pool construction 

    把每个草地与 S 相连,花费为dig,每个洞与 T 相连,花费为

    然后对于每个两个相邻的点连一条权值为 build 的边。

    求最小割,就是把草和洞分开的花费。

    因为只有三种割的情况:

    割S与草之间的边,那么这个草就与T相连了。所以花费需要dig。

    割T与洞之间的边。同理。

    割两个相邻的点之间的边。很显然,如果他们连着同一个点(源点或者汇点),那么他们是不会被割开的。

    所以只有他们连着不同的点的时候,才会需要花费build割开。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    const int N = 55;
    const int maxn = N*N+2+100;
    const int maxm = maxn*4*2;
    const int INF=0x3f3f3f3f;
    int g[N][N];
    int n,m,dig,fil,bui;
    int S, T;
    int ans = 0;
    
    struct Dinic{
        int head[maxn],Next[maxm],to[maxm],cap[maxm],flow[maxm];
        int sz,n,m,s,t;
        bool vis[maxn];
        int cur[maxn],d[maxn];
        void init(int n){
            this->n=n;
            memset(head,-1,sizeof(head));
            this->sz=-1;
        }
        void add_edge(int a,int b,int c){
            ++sz;
            to[sz]=b;
            cap[sz]=c;flow[sz]=0;
            Next[sz]=head[a];head[a]=sz;
            ++sz;
            to[sz]=a;
            cap[sz]=c;flow[sz]=c;
            Next[sz]=head[b];head[b]=sz;
        }
        bool BFS(){
            memset(vis,0,sizeof(vis));
            queue<int>Q;
            vis[s]=1;
            d[s]=0;
            Q.push(s);
            while(!Q.empty()){
                int u=Q.front();Q.pop();
                for(int i=head[u];i!=-1;i=Next[i]){
                    int v=to[i];
                    if(!vis[v]&&cap[i]>flow[i]){
                        vis[v]=1;
                        d[v]=d[u]+1;
                        Q.push(v);
                    }
                }
            }
            return vis[t];
       }
        int DFS(int x,int a){
            if(x==t||a==0)return a;
            int Flow=0,f;
            for(int& i=cur[x];i!=-1;i=Next[i]){
                int v=to[i];
                if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){
                    Flow+=f;
                    flow[i]+=f;
                    flow[i^1]-=f;
                    a-=f;
                    if(a==0)break;
                }
            }
            return Flow;
        }
        int Maxflow(int s,int t){
            this->s=s,this->t=t;
            int Flow=0;
            while(BFS()){
                for(int i=0;i<=n;i++)
                 cur[i]=head[i];
    
                Flow+=DFS(s,INF);
            }
            return Flow;
        }
    }dinic;
    
    inline int id(int x, int y)
    {
        return (x-1)*m + y;
    }
    
    int main()
    {
        int t;
        scanf("%d", &t);
        for (int ca = 1; ca <= t; ca ++)
        {
            scanf("%d%d",&m,&n);
            scanf("%d%d%d", &dig, &fil, &bui);
            ans = 0;
            dinic.init(n*m+3);
            S = n*m+1, T = n*m+2;
    
            for (int i = 1; i <= n; i++)
            {
                char x;
                for (int j = 1; j <= m; j++)
                    scanf(" %c", &x), g[i][j] = x=='#' ? 1:0;
            }
    
            int dx[] = {1, 0, 0, -1}, dy[] = {0, 1, -1, 0};
    
            for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
            {
                if (i == 1 || j == 1 || i == n || j == m)
                {
                    if (!g[i][j]) ans += fil, g[i][j] = 1;
                    dinic.add_edge(S, id(i, j), INF);
                }
                else if (g[i][j]) dinic.add_edge(S, id(i, j), dig);
                else dinic.add_edge(id(i, j), T, fil);
    
                for (int k = 0; k < 4; k++)
                {
                    int Fx = i+dx[k], Fy = j+dy[k];
                    if (Fx < 1 || Fx > n || Fy < 1 || Fy > m) continue;
                    dinic.add_edge(id(i, j), id(Fx, Fy), bui);
                }
            }
    
            ans += dinic.Maxflow(S, T);
            printf("%d
    ", ans);
        }
    
    return 0;
    }
    View Code

    模板题:CodeVS 1993 草地排水

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    const int maxn=100000+10;
    const int INF=2147000000;
    
    struct Dinic
    {
        int head[maxn],Next[maxn],to[maxn],cap[maxn],flow[maxn];
        //cap:容量, flow:流量
        int sz,n,m,s,t;
        bool vis[maxn];
        int cur[maxn],d[maxn]; //d:depth cur当前弧优化
        void init(int nn,int mm)
        {
            n=nn, m=mm;
            memset(head,-1,sizeof(head));
            sz=-1; //注意 方便亦或找反向边
        }
        
        void add_edge(int a,int b,int c)
        {
            ++sz;
            to[sz]=b, Next[sz]=head[a], head[a]=sz;
            cap[sz]=c, flow[sz]=0;
            
            ++sz;
            to[sz]=a, Next[sz]=head[b];head[b]=sz;
            cap[sz]=c, flow[sz]=c; //正向的增加,反向的减少
        }//加双向边
        
        bool BFS()
        {
            memset(vis,0,sizeof(vis));
            queue<int>Q;
            vis[s]=1;
            d[s]=0;
            Q.push(s);
            while(!Q.empty()){
                int u=Q.front();Q.pop();
                for(int i=head[u];i!=-1;i=Next[i]){
                    int v=to[i];
                    if(!vis[v]&&cap[i]>flow[i]){
                        vis[v]=1;
                        d[v]=d[u]+1;
                        Q.push(v);
                    }
                }
            }
            return vis[t];
        }//求深度
        
        int DFS(int x,int a){
            if(x==t||a==0)return a;//当前增广路上的最小残量
            int Flow=0,f;
            for(int& i=cur[x];i!=-1;i=Next[i]){
                int v=to[i];
                if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){
                    Flow+=f;
                    flow[i]+=f;
                    flow[i^1]-=f;//
                    a-=f;
                    if(a==0)break;
                }
            }
            return Flow;
        }//增广路
        
        int Maxflow(int ss,int tt)
        {
            s=ss, t=tt;
            int Flow=0;
            while(BFS())
            {
                for(int i=0;i<=n;i++) cur[i]=head[i];
                Flow+=DFS(s,INF);
            }
            return Flow;
        }
        
    }dinic;
    
    int n,m;
    int main()
    {
        scanf("%d%d",&m,&n);
        dinic.init(n, m);
        int a, b, c;
        for(int i = 1; i <= m; i++){
            scanf("%d%d%d", &a, &b, &c);
            dinic.add_edge(a, b, c);
        }
        int ans = dinic.Maxflow(1, n);
        cout<<ans<<endl;
        
    return 0;
    }

    HDU - 5889  Barricade

    先跑一遍最短路,然后从最短路上的边中跑最小割。

    TLE代码。。。我也不知道为什么会TLE。以后再改。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    
    #define mms(k, x) memset(k, (x), sizeof(k))
    
    using namespace std;
    const int maxn = 10000+10;
    const int maxm = 2*100000+10;
    const int INF = 0x3f3f3f3f;
    
    struct Dinic
    {
        int head[maxm],Next[maxm],to[maxm],cap[maxm],flow[maxm];
        //cap:容量, flow:流量
        int sz,n,m,s,t;
        bool vis[maxn];
        int cur[maxn],d[maxn]; //d:depth cur当前弧优化
        void init(int nn,int mm)
        {
            n=nn, m=mm;
            mms(head, -1);
            sz=-1; //注意 方便亦或找反向边
        }
    
        void add_edge(int a,int b,int c)
        {
            ++sz;
            to[sz]=b, Next[sz]=head[a], head[a]=sz;
            cap[sz]=c, flow[sz]=0;
    
            ++sz;
            to[sz]=a, Next[sz]=head[b];head[b]=sz;
            cap[sz]=c, flow[sz]=c; //正向的增加,反向的减少
        }//加双向边
    
        bool BFS()
        {
            memset(vis,0,sizeof(vis));
            queue<int>Q;
            vis[s]=1;
            d[s]=0;
            Q.push(s);
            while(!Q.empty())
            {
                int u=Q.front(); Q.pop();
                for(int i = head[u]; i != -1; i = Next[i])
                {
                    int v = to[i];
                    if(!vis[v] && cap[i] > flow[i])
                    {
                        vis[v]=1;
                        d[v]=d[u]+1;
                        Q.push(v);
                    }
                }
            }
            return vis[t];
        }//求深度
    
        int DFS(int x,int a){
            if(x==t||a==0)return a;//当前增广路上的最小残量
            int Flow=0,f;
            for(int& i=cur[x];i!=-1;i=Next[i]){
                int v=to[i];
                if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){
                    Flow+=f;
                    flow[i]+=f;
                    flow[i^1]-=f;//
                    a-=f;
                    if(a==0)break;
                }
            }
            return Flow;
        }//增广路
    
        int Maxflow(int ss,int tt)
        {
            s=ss, t=tt;
            int Flow=0;
            while(BFS())
            {
                for(int i=0;i<=n;i++) cur[i]=head[i];
                Flow+=DFS(s,INF);
            }
            return Flow;
        }
    
    }dinic;
    
    int v[maxm], nxt[maxm], last[maxm], l[maxm], u[maxm];
    int dis[maxn], vis[maxn];
    int tot = 0;
    
    void build(int x, int y, int z)
    {
        tot++, v[tot] = y;
        nxt[tot] = last[x], last[x] = tot, l[tot] = z;
        u[tot] = x;
    }
    
    void init()
    {
        tot = 0, mms(last, 0);
    }
    
    int relax(int x, int y, int tmp)
    {
        if (dis[x]+1 < dis[y])
        {
            dis[y] = dis[x] + 1;
            return 1;
        }
        return 0;
    }
    
    void SPFA(int k)
    {
        queue<int> q;
        mms(dis, INF), mms(vis, 0);
        q.push(k), dis[k] = 0, vis[k] = 1;
    
        while(!q.empty())
        {
            int x = q.front(), y;
            q.pop();
            for (int i = last[x]; i; i = nxt[i])
            {
                int y = v[i];
                if (relax(x, y, i) && !vis[y]) q.push(y), vis[y] = 1;
            }
            vis[x] = 0;
        }
    }
    
    int n,m;
    int main()
    {
        int t;
        scanf("%d", &t);
        for (int ca = 1; ca <= t; ca++)
        {
            init();
            scanf("%d%d",&m,&n);
            dinic.init(n, m);
            int a, b, c;
            for(int i = 1; i <= m; i++)
            {
                scanf("%d%d%d", &a, &b, &c);
                build(a, b, c);
                build(b, a, c);
            }
    
            SPFA(1);
            for (int i = 1; i <= tot; i+=2)
            {
                int x = u[i], y = v[i], c = l[i];
                if (dis[y]-dis[x] == 1)
                    dinic.add_edge(x, y, c);
                else if (dis[x]-dis[y] == 1)
                    dinic.add_edge(y, x, c);
            }
    
            int ans = dinic.Maxflow(1, n);
            printf("%d
    ", ans);
        }
    return 0;
    }
  • 相关阅读:
    openstack常见问题
    30 个 Openstack 经典面试问题和解答
    linux系统内存爆满的解决办法!~
    iostat详解
    线上应用故障排查之一:高CPU占用
    对OpenStack运维架构的总结(转)
    zabbix基本监控各指标简解
    创建 OpenStack云主机
    centos7系统中忘记了root管理员账号密码的解决方式(转)
    MySQL高可用架构之MHA
  • 原文地址:https://www.cnblogs.com/ruthank/p/9535317.html
Copyright © 2011-2022 走看看