网络流24题

P2756 飞行员配对方案问题

简单二分图匹配

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int N=1e3+5;
int gp[N][N],match[N],vis[N];
int n,m;
bool findpath(int u){
    for(int i=m+1;i<=n+m;i++){
        if(gp[u][i]&&!vis[i]){
            vis[i]=1;
            if(!match[i]||findpath(match[i])){
                match[i]=u;
                return 1;
            }
        }
    }
    return 0;
}   
void init(){
    memset(gp,0,sizeof gp);
    memset(match,0,sizeof match);
}
int main(){
    init();
    scanf("%d %d",&m,&n);
    int u,v;
    while(~scanf("%d %d",&u,&v)){
        if(u+v<0)break;
        gp[u][v]=1;
    }
    vector<int>ans;
    for(int i=1;i<=m;i++){
    
        memset(vis,0,sizeof vis);
        if(findpath(i))ans.pb(i);
    
    }
    for(int i=m+1;i<=n+m;i++){
        if(match[i])match[ match[i] ]=i;
    }
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++){
        printf("%d %d\n",ans[i],match[ ans[i] ]);
    }

    // system("pause");
    return 0;
}
View Code

P4015 运输问题

easy

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+50;
const int inf=0x3f3f3f3f;
int a[200],b[200],c[200][200];
int n,m,S,T;
int mincost;
struct Dinic{
    int head[N],dis[N],pre[N],flow[N],last[N];
    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 w,int flow){
    e[ecnt].v=v;e[ecnt].w=w;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++;
    }

    bool 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;
    }
    void  MCMF(){
        mincost=0;
        while(spfa()){
            int cur=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];
            }
        }
    }

}dinic;  

void init_add(int t){
    for(int i=1;i<=m;i++){
        dinic.addedge(S,i,0,a[i]);
        dinic.addedge(i,S,0,0);
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            dinic.addedge(i,j+m,t*c[i][j],inf);
            dinic.addedge(j+m,i,-c[i][j]*t,0);
        }
    }
    for(int i=1;i<=n;i++){
        dinic.addedge(i+m,T,0,b[i]);
        dinic.addedge(T,i+m,0,0);
    }
}
int main(){
    scanf("%d %d",&m,&n);
    S=0,T=10005;
    for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)scanf("%d",&b[i]);
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                scanf("%d",&c[i][j]);
            }
        }

        dinic.init();
        init_add(1);
        dinic.MCMF();
        printf("%d\n",mincost);

        dinic.init();
        init_add(-1);
        dinic.MCMF();

        printf("%d\n",-mincost);
        // system("pause");
    return 0;
}
View Code

P2764 最小路径覆盖问题

考虑最初有n个路径穿过n个点,那么如果两两之间有边,就可以把路径合并,做法就是把每个点拆成两个点,如果有边就连一下,表示联通。

跑一遍最大流,实际上就是合并尽可能多的路径。

 输出路径:把一条路径的点合并到一个并查集里,然后起点标记为父结点,递归输出。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f;
struct edge{int v,next;}e[N*10];
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++;
    e[ecnt].v=u;e[ecnt].flow=0;e[ecnt].next=head[v];head[v]=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;
    }

    int fa[N];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void build(int x,int y){int dx=find(x),dy=find(y);if(dx!=dy)fa[dx]=dy;}
    
    void print(int u){
        printf("%d ",u);
        for(int i=head[u];~i;i=e[i].next){
            if(e[i].flow==0&&e[i].v>n){
                print(e[i].v-n);
            }
        }
    }
    
    void work(){
        for(int i=1;i<=n;i++)fa[i]=i;
        int ans=maxflow();
            for(int u=1;u<=n;u++){
                for(int i=head[u];~i;i=e[i].next){
                    // if(e[i].v==T)continue;
                    if(e[i].flow==0&&e[i].v>n){
                        build(e[i].v-n,u);
                    }
                }
            
            }

        for(int cur=1;cur<=n;cur++){
            if(find(cur)==cur){print(cur);puts("");}
        }

        printf("%d\n",n-ans);
    }
}dinic;  
int main(){
    scanf("%d %d",&n,&m);
    dinic.init();
    S=0,T=2*n+50;
    
    int u,v;
    while(m--){
        scanf("%d %d",&u,&v);
        dinic.addedge(u,v+n,1);
    }
    
    for(int i=1;i<=n;i++){
        dinic.addedge(i+n,T,1);
    }
    for(int i=1;i<=n;i++){
        dinic.addedge(S,i,1);
    }
    dinic.work();
    // system("pausea");
    return 0;
}
View Code 

P1251 餐巾计划问题

 

posted @ 2020-05-11 16:17  无声-黑白  阅读(124)  评论(0编辑  收藏  举报