zoukankan      html  css  js  c++  java
  • 网络流24题-飞行员配对方案问题-二分图最大匹配

      这道题,是个人都看得出来,是求一个二分图的最大匹配。

      但是网络流24题嘛,我们考虑一下用网络流的方法做。

      一般二分图的题,转网络流做,都需要建立一个起点和汇点。然后求一个最大流,这个最大流就是二分图的最大匹配。

      我用的是Edmonds-Karp算法bfs版本

      代码

    #include<iostream>
    #include<string.h>
    #include<stdio.h>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int n,m,s,t,tot,maxflow;
    const int inf = 1<<29,N=2010,M=20010;
    int head[N],ver[M],edge[M],Next[M],v[N],incf[N],pre[N];
      //邻接表最后一个点(表头),下一个节点,流量,邻接表,数组,增广路上各边最小剩余容量,路径记录
    void add(int x,int y,int z){
       ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;//正向边
       ver[++tot]=x,edge[tot]=0,Next[tot]=head[y],head[y]=tot;//反向边
    }
    bool bfs(){
      memset(v,0,sizeof(v));
      queue<int>q;
      q.push(s);
      v[s]=1;
      incf[s]=inf;//增广路上各边最小剩余容量
      while(q.size()){
        int x=q.front();
        q.pop();
        for (int i=head[x];i!=-1;i=Next[i])//开始广度遍历
           if (edge[i]){//流量不为0
              int y=ver[i];
              if(v[y])continue;//这条边在当前的BFS里面已经走过了
              incf[y]=min(incf[x],edge[i]);
              pre[y]=i;//记录前驱,方便把方案保存下来
              q.push(y),v[y]=1;
              if (y==t)return 1;//成功
           }
      }
      return 0;//失败
    }
    void update(){
      int x=t;
      while(x!=s){
         int i=pre[x];
         edge[i]-=incf[t];//更新流量
         edge[i^1]+=incf[t];//更新反向流量
         x=ver[i^1];
      }
      maxflow+=incf[t];
    }
    int main(){
      int tmp1,tmp2;
      while(~scanf("%d%d",&m,&n)){
        memset(head,-1,sizeof(head));
        s=0,t=n+1,tot=1,maxflow=0;
        while(1){
            scanf("%d%d",&tmp1,&tmp2);
            if (tmp1==-1 && tmp2==-1)
                break;
            add(tmp1,tmp2,0x3f3f3f3f);
        }
        for (int i=1;i<=m;i++){
            add(s,i,1);
        }
        for (int i=m+1;i<=n;i++){
            add(i,t,1);
        }
        while(bfs())
            update();
        printf("%d
    ",maxflow);
        for (int i=2;i<=tot;i+=2){
            if((ver[i^1]!=s && ver[i]!=t)&&(ver[i]!=s && ver[i^1]!=t))//不能是直接指向起点和汇点的点
            if (edge[i^1]!=0)
            printf("%d %d
    ",ver[i^1],ver[i]);
        }
      }
      return 0;
    }

     留坑匈牙利算法

    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    UIButton组件
    九宫格
    window对象的创建
    UILabel的属性及方法
    javascript相关,格式转化
    MySQL分区分表相关知识摘要
    redis简单笔记
    PHP常用设计模式
    在nginx上面部署多个项目
    把自己的项目上传到svn上面
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/10434865.html
Copyright © 2011-2022 走看看