zoukankan      html  css  js  c++  java
  • 网络流learning

    上次学习网络流还是大一的下学期,之后就被从图论分出来交给队友了

    然而吉林一战,队友在深圳读研而不能来,于是需要自己学习一下,争取在比赛前看完网络流建模汇总和一些总结,升华一下。

    同时记录一下自己做过的题目和想法,相互映照,得出结论

    POJ1149

    时间看来是很老的题,不过还没有见过,一开始想出来的办法是给人流量,让圈互相给max边,但是后来发现不对,因为如果先给圈边的话,人的次序就不会对ans造成影响,对于这类有时间限制的题,可以对一些被时间影响到的点进行“持久化”,第i+1个状态的流量由第i个状态的流量转移而来,虽然点数变成了点数*时间,但是在二分图下很快,而n*m是1e5,很明显的暗示。

    采用dinic进行初始学习

    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    #include<stack>
    #include<string>
    #include<queue>
    using namespace std;
    #define pb push_back
    
    #define rep(i, a, b) for (int i=a;i<=b;++i)
    
    const int N = 100 * 1000 + 100 + 100 + 5 ;
    const int M = 100 * 1000 * 5 + 5 ;
    const int INF = 999999999 ;
    int src , des , e , head[N] , dis[N] ;
    int n , m ;
    
    struct Edge {
        int v,cap,next;
        Edge(){}
        Edge(int vv,int cc,int ne) {
            v=vv;cap=cc;next=ne;
        }
    } ed[M] ;
    void init() {
        e = 0 ;
        memset(head,-1,sizeof(head)) ;
    }
    int bfs() {
        memset(dis,0,sizeof(dis)) ;
        dis[src] = 1 ;
        queue<int>q;
        q.push(src) ;
        while(!q.empty()) {
            int x = q.front(); q.pop() ;
            for(int i = head[x] ; i != -1 ; i = ed[i].next) {
                int v = ed[i].v ;
                if(ed[i].cap && dis[v] == 0) {
                    dis[v] = dis[x] + 1 ;
                    if(v == des) {
                        return 1 ;
                    }
                    q.push(v) ;
                }
            }
        }
        return 0 ;
    }
    int dfs(int s,int f) {
        if(s == des) return f;
        int tmp,cost = 0 ;
        for(int i = head[s] ; i != -1 ; i = ed[i].next) {
            int v = ed[i].v ;
            if(ed[i].cap && dis[s] == dis[v] - 1) {
                tmp = dfs(v,min(f-cost,ed[i].cap)) ;
                if(tmp > 0) {
                    ed[i].cap -= tmp;
                    ed[i^1].cap += tmp ;
                    cost += tmp ;
                    if (f == cost)
                        break ;
                }
                else dis[v] = -1 ;
            }
        }
        return cost ;
    }
    int Dinic() {
        int ans = 0 ;
        while(bfs()) {
            ans += dfs(src,INF) ;
        }
        return ans ;
    }
    
    void add(int u,int v,int cap) {
        ed[e] = Edge(v,cap,head[u]) ;
        head[u] = e++ ;
        ed[e] = Edge(u,0,head[v]) ;
        head[v] = e++ ;
    }
    
    int a[1050] ;
    int b[105][1050] ;
    int c[105] ;
    int main () {
        while(scanf("%d%d" , &m,&n) != EOF) {
            init();
            src = 0 ;
            des = m * n + n + n + 1 ;
            rep(i,1,m) {
                scanf("%d" , &a[i]) ;
            }
    
            /// src = 0 ;
            /// pig 1~m m+1~m*2 ... m*n
            /// peo1 m*n + 1~ m*n + n
            /// peo2 m*n + n + 1 ~ m*n + n + n
            /// des m*n+n*2+1
            rep(i,1,n) {
                int nu ; scanf("%d" , &b[i][0]) ;
                rep(j,1,b[i][0]) {
                    scanf("%d" , &b[i][j]) ;
                }
                scanf("%d" , &c[i]) ;
            }
    
            rep(i,1,m) {
                add(src, i, a[i]) ;
            }
    
            rep(i,1,n-1) {
                rep(j,1,m) {
                    add((i-1)*m+j,(i)*m+j,INF) ;
                }
                rep(j,1,b[i][0]) {
                    rep(k,1,b[i][0]) {
                        // if(j == k) continue ;
                        int u = (i-1)*m + b[i][j];
                        int v = (i)*m + b[i][k] ;
                        add(u,v, INF) ;
                    }
                }
            }
    
            rep(i,1,n) {
                int u = m * n + i ;
                int v = m * n + n + i ;
                add(u,v, c[i]) ;
            }
    
            rep(i,1,n) {
                int v = m * n + i ;
                rep(j,1,b[i][0]) {
                    int u = (i - 1) * m + b[i][j] ;
                    add(u,v, INF) ;
                }
            }
    
            rep(i,1,n) {
                int u = m * n + n + i ;
                int v = des ;
                add(u,v, INF) ;
            }
    
            printf("%d
    " , Dinic()) ;
        }
    }
    

     感想:千万不能写错板子,dinic其实是这样的,bfs确定可流,dfs来找出最大的那条流量边,多次dfs其实是M*N*M的复杂度 dfs数量*增广时间

     poj2391

    这个比较老,一眼就能看出是floyd取minDis然后建二分图,不拆点肯定是错的,甚至连时间都限制不了?

    一个坑在于,每次二分都需要重新加边,因为每次图的状态都是残余流量,当然因为i+i^1的cap其实就是i,所以也可以直接扫边更新,不过扫边更新后需要更改板子,需要判断的比较多

    后来在比赛的前一天晚上看完了网络流建模汇总,比赛不出意料的没有出网络流。。

    工作做完了在学校应该会补完这一部分,为了青岛而努力一下,LCT似乎也是很有趣的算法,不过也需要看一下书。

                                                                                                        to be continue....

    因为备战EC,自己需要负责网络流,所以重新捡起,主要学习最小费用流

    POJ3680 

    很经典的题型,200个区间中选一些,获得她们的权值,这些区间不能将任意一个点覆盖K次以上

    思考发现,如果仅仅从区间的角度上来考虑,将区间化点,是无法在MCMF的过程中控制点被覆盖的次数的,总不能给每个点记录当前被覆盖多少次然后check是否连通。。

    所以从点的角度思考,假设有一条从最左点依次向右的流(i,i+1),流量为k,那么每个区间其实是将l到r的流量都减一,然后直接从l跨越到r,因为到l的流量也是从0点的K开始不断的衰减,所以直接进行下去就可以,即建一条边(l,r,1,-c),最后跑0~m的MCMF

    int main () {
        int TT ; scanf("%d" , &TT) ;
        while(TT--){
            int n , k ;
            scanf("%d%d" , &n,&k) ;
            vector<int>ls;
            rep(i,1,n) {
                scanf("%d%d%d" , &l[i],&r[i],&c[i]) ;
                ls.pb(l[i]) ;
                ls.pb(r[i]) ;
            }
            sort(ls.begin(),ls.end());
            ls.erase(unique(ls.begin(),ls.end()),ls.end()) ;
            rep(i,1,n) {
                l[i] = lower_bound(ls.begin(),ls.end(),l[i])-ls.begin()+1;
                r[i] = lower_bound(ls.begin(),ls.end(),r[i])-ls.begin()+1;
            }
            init() ;
            int m = ls.size() ;
            for(int i = 0 ; i <= m ; i ++ ) {
                addEdge(i,i+1,k,0) ;
            }
            for(int i = 1 ; i <= n ; i ++ ) {
                addEdge(l[i],r[i],1,-c[i]) ;
            }
            int cost,flow;
            MCMF(0,m+1,cost,flow);
            printf("%d
    " , -cost) ;
        }
    }
    

      

    SPOJ371 

    n(1000)个箱子里有总共n个小球,每次可以移动一个球到相邻箱子中,问多少步可以让每个箱子最多一个球。

    建图比较好想,把球当作流量,des可以从每个箱子中回收一个流量,src会给每个箱子a[i]的流量,流量在箱子之间穿梭的cost是1

    建图 (src,i,a[i],0) (i,i-1,INF,1)(i,i+1,INF,1)(i,des,1,0)

    不过复杂度是玄学的,spfa是nmm的,t还有20组,看起来有1e10,但是由于spfa复杂度很玄,还是过了

    int main () {
        int TT ; scanf("%d" , &TT) ;
        while(TT--){
            int n ; scanf("%d" , &n) ;
            rep(i,1,n) scanf("%d" , &a[i]) ;
            init() ;
            rep(i,1,n) {
                addEdge(0,i,a[i],0) ;
                addEdge(i,n+1,1,0) ;
                int le=i-1;
                if(le==0)le=n;
                addEdge(i,le,INF,1);
                le=i+1;
                if(le==n+1)le=1;
                addEdge(i,le,INF,1);
            }
            int cost,flow;
            MCMF(0,n+1,cost,flow);
            printf("%d
    ",cost);
        }
    }
    

      

  • 相关阅读:
    Windows关于文件句柄数的限制
    python 的未来5-10年的就业方向
    想着给要做的软件起一个名儿~
    sql server 特殊sql
    字节序之大小端_Intelx86是小端_网络传输是大端
    维基百科Wikipedia镜像网站列表
    NodeJS开启GZIP功能
    SqlServer2008 跨服务器同步数据
    Asp.net中的ViewState用法
    JAVA Netty入门Demo实例代码(自写测试可用)实现客户端服务器端互传数据
  • 原文地址:https://www.cnblogs.com/rayrayrainrain/p/9681381.html
Copyright © 2011-2022 走看看