zoukankan      html  css  js  c++  java
  • [kuangbin带你飞]专题十一 网络流

    B - Dining

     POJ - 3281 

    首先二分图的多重匹配匈牙利算法是不行的,无法最优。

     直接在构图跑最大流也是不行的:会出现限制。

     每一个人拆成两个点,流量为1,增加流量限制,保证不会变大。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    using namespace std;
    typedef double db;
    const db eps=1e-6;
    const int inf=0x3f3f3f3f;
    const int N=1e4+5;
    int n,m,S,T;
    struct Dinic{
        int head[N],dep[N];
        int ecnt; 
        struct edge{
            int v,flow,next;
        }e[N*10];
    
        void init(){
            memset(head, -1, sizeof head);
            ecnt = 0;
        }
        void addedge(int u, int v, int  flow) {
        e[ecnt].v=v;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++;
        }
        bool BFS(){//分层图找增广路
            memset(dep,0,sizeof dep);
            queue<int>Q;
            Q.push(S);dep[S]=1;
            while(!Q.empty()){
                int u=Q.front();Q.pop();
                for(int i=head[u];~i;i=e[i].next){
                    if(e[i].flow&&!dep[e[i].v]){
                        dep[e[i].v]=dep[u]+1;
                        Q.push(e[i].v);
                    }
                }
            }
            return dep[T];
        }
        int DFS(int u, int f){//推进新流
            if(u==T||f==0)return f;
            int w,used=0;
            for(int i=head[u];~i;i=e[i].next){
                if(e[i].flow&&dep[e[i].v]==dep[u]+1){
                    w=DFS(e[i].v,min(f,e[i].flow));//多路增广
                    e[i].flow-=w;e[i^1].flow+=w;
                    used+=w;f-=w;
                }
            }
            if(!used)dep[u]=-1;//炸点优化
            return used;
        }
        int maxflow() {
            int ans=0;
            while(BFS()){
                ans+=DFS(S,inf);
            }
            return ans;
        }
    }dinic; 
    int main(){
        int F,D;
        scanf("%d %d %d",&n,&F,&D);
        S=0,T=2*n+F+D+10;
        dinic.init();
        for(int i=1;i<=F;i++){
            dinic.addedge(S,i,1);
            dinic.addedge(i,S,0);
        }
        // for(int i=1;i<=n;i++)
        for(int i=1,A,B,v;i<=n;i++){
            scanf("%d %d",&A,&B);
            while(A--){scanf("%d",&v);dinic.addedge(v,i+F,1);dinic.addedge(i+F,v,0);}
            dinic.addedge(i+F,i+F+n,1);
            dinic.addedge(i+F+n,i+F,0);
            while(B--){scanf("%d",&v);dinic.addedge(i+F+n,v+2*n+F,1);dinic.addedge(v+2*n+F,i+F+n,0);}
    
        }
        for(int i=1;i<=D;i++){
        dinic.addedge(i+2*n+F,T,1);   
        dinic.addedge(T,i+2*n+F,0);   
        }
        printf("%d
    ",dinic.maxflow());
    
        // system("pause");
        return 0;
    }
    View Code

    D - Going Home

     POJ - 2195 

    一张网格图,给定若干个人和房子,求所有人走到房子的最小花费。

    把人和房子连起来,跑一遍费用流即可。

    #include <cstdio>
    // #include<bits/stdc++.h>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    const int inf=0x3f3f3f3f;
    const int N=1e4+50;
    int n,m,S,T,maxflow,mincost;
    struct Dinic{
        int head[N],dep[N],dis[N],pre[N],flow[N],last[N];
        //dep记录分层图,pre点前驱,flow点的流,last点的前一条边,dis表示费用
        bool inq[N];
        int ecnt; 
        struct edge{
            int v,w,flow,next;
        }e[N*10];
        void init(){
            memset(head, -1, sizeof head);
            ecnt = 0;
        }
        void addedge(int u,int v,int flow,int w){
        e[ecnt].v=v;e[ecnt].w=w;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++;
        }
        bool spfa(){//spfa找增广路
            memset(dis,inf,sizeof dis);
            memset(flow,inf,sizeof flow);
            memset(inq,0,sizeof inq);
            queue<int>Q;
            Q.push(S);inq[S]=1;dis[S]=0;pre[T]=-1;
            while(!Q.empty()){
                int u=Q.front();Q.pop();inq[u]=0;
                for(int i=head[u];~i;i=e[i].next){
                    int v=e[i].v,w=e[i].w;
                    if(e[i].flow>0&&dis[v]>dis[u]+w){
                        dis[v]=dis[u]+w;pre[v]=u;last[v]=i;
                        flow[v]=min(flow[u],e[i].flow);
                        if(!inq[v]){
                        Q.push(v);inq[v]=1;
                        }
                    }
                }
            }
            return pre[T]!=-1;
        }
        int  MCMF(){
         maxflow=mincost=0;
            while(spfa()){//推进新流
                int cur=T;
                maxflow+=flow[T];
                mincost+=flow[T]*dis[T];
                while(cur!=S){//汇点向前回溯
                    e[last[cur]].flow-=flow[T];
                    e[last[cur]^1].flow+=flow[T];
                    cur=pre[cur];
                }
            }
            return mincost;
        }
    }dinic;  
    char gp[500][500];
    vector<pair<int,int> >H,M;
    int get(int a,int b,int c,int d){
        return abs(a-c)+abs(b-d);
    }
    int getid(int x,int y){return (x-1)*m+y;}
    int main(){
        while(~scanf("%d %d",&n,&m),n+m){
            dinic.init();
            H.clear();
            M.clear();
            for(int i=1;i<=n;i++){
                getchar();
                for(int j=1;j<=m;j++){
                    scanf("%c",&gp[i][j]);
                    if(gp[i][j]=='m')M.pb(mp(i,j));
                    else if(gp[i][j]=='H')H.pb(mp(i,j));
                }
            }
            // cout<<"mp "<<endl;
            // for(int i=1;i<=n;i++){
            //     for(int j=1;j<=m;j++){
            //         cout<<gp[i][j];
            //     }
            //     cout<<endl;
            // }
            // cout<<endl;
            // cout<<"M :"<<M.size()<<endl;
            // cout<<"H "<<H.size()<<endl;
            S=0,T=n*m+10;
            for(int i=0;i<H.size();i++){
                int x=H[i].fi,y=H[i].se;
                int id=getid(x,y);
                dinic.addedge(S,id,1,0);
                dinic.addedge(id,S,0,0);
            }
    
            for(int i=0;i<H.size();i++){
                int hx=H[i].fi,hy=H[i].se;
                int hs=getid(hx,hy);
                for(int j=0;j<M.size();j++){
                int mx=M[j].fi,my=M[j].se;
                int me=getid(mx,my);
                int cost=get(hx,hy,mx,my);
                dinic.addedge(hs,me,1,cost);
                dinic.addedge(me,hs,0,-cost);
                }
            }
            for(int i=0;i<M.size();i++){
                int x=M[i].fi,y=M[i].se;
                int id=getid(x,y);
                dinic.addedge(id,T,1,0);
                dinic.addedge(T,id,0,0);
            }        
            printf("%d
    ",dinic.MCMF());
        }
            // system("pause");
        return 0;
    }
    View Code

    E - Minimum Cost

     POJ - 2516 

    m个货店,n个人,每个人需要若干个物品,每个点可以提供若干个物品,求满足所有人需求的最小花费。

    开始想直接暴力建 kn 个人点,km个店点,一共有5000个点,TLE

    首先特判,如果k个节点提供的小于需要的,直接输出-1。 

    考虑k种商品相互独立,互不关联,跑k次费用流,将结果累加即可。

    #include <cstdio>
    // #include<bits/stdc++.h>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    const int inf=0x3f3f3f3f;
    const int N=1e5+50;
    int n,m,K,S,T,maxflow,mincost;
    struct Dinic{
        int head[N],dep[N],dis[N],pre[N],flow[N],last[N];
        //dep记录分层图,pre点前驱,flow点的流,last点的前一条边,dis表示费用
        bool inq[N];
        int ecnt; 
        struct edge{
            int v,w,flow,next;
        }e[N*10];
        void init(){
         // for(int i=0;i<K*(m+n);i++)head[i]=-1;
            // memset(head, -1, sizeof head);
            for(int i=0;i<=2*m*n*K*K;i++)head[i]=-1;
            ecnt = 0;
        }
        void addedge(int u,int v,int flow,int w){
        e[ecnt].v=v;e[ecnt].w=w;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++;
        }
        bool spfa(){//spfa找增广路
            memset(dis,inf,sizeof dis);
            memset(flow,inf,sizeof flow);
            memset(inq,0,sizeof inq);
            queue<int>Q;
            Q.push(S);inq[S]=1;dis[S]=0;pre[T]=-1;
            while(!Q.empty()){
                int u=Q.front();Q.pop();inq[u]=0;
                for(int i=head[u];~i;i=e[i].next){
                    int v=e[i].v,w=e[i].w;
                    if(e[i].flow>0&&dis[v]>dis[u]+w){
                        dis[v]=dis[u]+w;pre[v]=u;last[v]=i;
                        flow[v]=min(flow[u],e[i].flow);
                        if(!inq[v]){
                        Q.push(v);inq[v]=1;
                        }
                    }
                }
            }
            return pre[T]!=-1;
        }
        int MCMF(){
         maxflow=mincost=0;
            while(spfa()){//推进新流
                int cur=T;
                maxflow+=flow[T];
                mincost+=flow[T]*dis[T];
                while(cur!=S){//汇点向前回溯
                    e[last[cur]].flow-=flow[T];
                    e[last[cur]^1].flow+=flow[T];
                    cur=pre[cur];
                }
            }
            return mincost;
        }
    }dinic;
    int need[100],supply[100];
    int mt[100][100][100],from[100][100],to[100][100];
    bool check(){
        for(int i=1;i<=K;i++)if(supply[i]<need[i])return 0;
        return 1;
    } 
    int main(){
        while(~scanf("%d %d %d",&n,&m,&K),n+m+K){
            memset(need,0,sizeof need);
            memset(supply,0,sizeof supply);
            for(int i=1;i<=n;i++){
                for(int k=1;k<=K;k++){
                    scanf("%d",&to[i][k]);
                    need[k]+=to[i][k];
                }
            }
        for(int i=1;i<=m;i++){
            for(int k=1;k<=K;k++){
                    scanf("%d",&from[i][k]);
                    supply[k]+=from[i][k];
            }
        }
        for(int k=1;k<=K;k++){
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    scanf("%d",&mt[k][i][j]);
                }
            }
        }
        if(!check()){puts("-1");continue;}
        int ans=0;
        for(int k=1;k<=K;k++){
            dinic.init();S=0;T=m+n+50;
            for(int i=1;i<=m;i++){
                dinic.addedge(S,i,from[i][k],0);
                dinic.addedge(i,S,0,0);
            }
            for(int i=1;i<=m;i++){
                for(int j=1;j<=n;j++){
            dinic.addedge(i,m+j,inf,mt[k][j][i]);
            dinic.addedge(m+j,i,0,-mt[k][j][i]);
                       
                }
            }
            for(int i=1;i<=n;i++){
                dinic.addedge(m+i,T,to[i][k],0);
                dinic.addedge(T,m+i,0,0);
            }
            ans+=dinic.MCMF();
        }
        printf("%d
    ",ans);
        }
       // system("pause");
        return 0;
    }
    View Code

    G - Island Transport

     HDU - 4280 

    。。看错题了,题目保证流没有相交,

    TLE的原因是因为本来是个无向边,非要拆成四条边肯定多了两倍时间 ,实际拆成两条边就行了。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include<bits/stdc++.h>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    using namespace std;
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    const int inf=0x3f3f3f3f;
    const int N=1e5+50;
    int n,m,S,T;
    struct Dinic{
        int head[N],dep[N];
        int ecnt; 
        struct edge{
            int v,flow,next;
        }e[N*10];
    
        void init(){
            memset(head, -1, sizeof head);
            ecnt = 0;
        }
    
        void addedge(int u, int v, int  flow) {
        e[ecnt].v=v;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++;
        }
    
        bool BFS(){//分层图找增广路
            memset(dep,0,sizeof dep);
            queue<int>Q;
            Q.push(S);dep[S]=1;
            while(!Q.empty()){
                int u=Q.front();Q.pop();
                for(int i=head[u];~i;i=e[i].next){
                    if(e[i].flow&&!dep[e[i].v]){
                        dep[e[i].v]=dep[u]+1;
                        Q.push(e[i].v);
                    }
                }
            }
            return dep[T];
        }
    
        int DFS(int u, int f){//推进新流
            if(u==T||f==0)return f;
            int w,used=0;
            for(int i=head[u];~i;i=e[i].next){
                if(e[i].flow&&dep[e[i].v]==dep[u]+1){
                    w=DFS(e[i].v,min(f,e[i].flow));//多路增广
                    e[i].flow-=w;e[i^1].flow+=w;
                    used+=w;f-=w;
                }
            }
            if(!used)dep[u]=-1;//炸点优化
            return used;
        }
        int maxflow() {
            int ans=0;
            while(BFS()){
                ans+=DFS(S,inf);
            }
            return ans;
        }
    }dinic;    
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            scanf("%d %d",&n,&m);
            int Min=inf,Max=-inf;
            for(int i=1,x,y;i<=n;i++){
                scanf("%d %d",&x,&y);
                if(x>Max){Max=x;T=i;}
                if(x<Min){Min=x;S=i;}
            }
            dinic.init();
            for(int i=1,u,v,f;i<=m;i++){
                scanf("%d %d %d",&u,&v,&f);
                dinic.addedge(u,v,f);
                // dinic.addedge(v,u,0);
                dinic.addedge(v,u,f);
                // dinic.addedge(u,v,0);
                   
            }
            printf("%d
    ",dinic.maxflow());
        }
       // system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    Python 资源大全中文版
    Life is short.,You need Python
    哪些 Python 库让你相见恨晚?
    中国裁判文书网全网最新爬虫分析
    关于pycharm导入其他项目时出现找不到python无法运行的问题
    禅道项目管理软件配置及使用教程
    curl
    fusionpbx 中文 汉化
    kafka operation
    golang包管理工具——glide
  • 原文地址:https://www.cnblogs.com/littlerita/p/12813601.html
Copyright © 2011-2022 走看看