从二分图最大匹配到二分图最优匹配

从二分图最大匹配到二分图最优匹配

  1. 二分图最大匹配

    1. 没啥说得,直接上代码。

    2. int vispipei[maxn],match[maxn];
      int dfspipei(int now)
      {
          for(int i=1;i<=nn;i++)
          if(dis[now][i])
          {
              int nex=i;
              if(!vispipei[nex])
              {
                  vispipei[nex]=1;
                  if(match[nex]==0 || dfspipei(match[nex]))
                  {
                      match[nex]=now;
                      return true;
                  }
              }
          }
          return false;
      }
      int solve()
      {
      	for(int i=1;i<=nn;i++)
              match[i]=0;
          int cnt=0;
          for(int i=1;i<=nn;i++)
          {
              for(int j=1;j<=nn;j++)
                  vispipei[j]=0;
              if(!dfspipei(i))
              	cnt++;
          }
          return cnt;
      }
      
    3. 使用的时候千万要注意把return写够!以及match和vis数组的清空!

    4. 应用

      1. 最小点覆盖=最大匹配
      2. 最小路径覆盖= ∣ V ∣ |V| V-最大匹配
      3. 最大独立集= ∣ V ∣ |V| V-最大匹配。最大独立集S 与 最小覆盖集T 互补
    5. 拓展

      1. 存在一种复杂度为 o ( n ∗ e ) o(\sqrt{n}*e) o(n e)的二分图最大匹配算法,名字为HK,其实本质上就是网络流了
      2. 我记得在我高二的时候听一个课,课上说了用网络流跑最大匹配就是这个复杂度。
      3. 如果非要写HK,HK的具体步骤为:
        1. BFS
          1. 首先把二分图染成黑色的点加到队列里。
          2. 对于每一个队列里的点 u u u,与它相连的点 v v v,如果 v v v没被访问过,首先深度设为 d e p [ u ] + 1 dep[u]+1 dep[u]+1
            1. 如果没被匹配,则找到了一条增广路,对 v v v就什么都不做最后 r e t u r n   t r u e return\ true return true
            2. 否则将与 v v v匹配的点,加到队列里。
        2. DFS
          1. 与匈牙利的类似,只不过要求 d e p [ v ] dep[v] dep[v] 必须是 d e p [ u ] + 1 dep[u]+1 dep[u]+1
  2. 二分图最优匹配

    1. 也没啥说得,直接上代码。

    2. int nn;
      int wx[maxn],wy[maxn],weight[maxn][maxn],st[maxn];
      int bel[maxn],visx[maxn],visy[maxn];
      int dfs(int u)
      {
          visx[u]=1;
          for(int v=1;v<=nn;v++)
          {
              if(visy[v]) continue;
              int t=wx[u]+wy[v]-weight[u][v];
              if(!t)
              {
                  visy[v]=1;
                  if(bel[v]==-1||dfs(bel[v]))
                  {
                      bel[v]=u;
                      return 1;
                  }
              }
              else if(st[v]>t)
                  st[v]=t;
          }
          return 0;
      }
         
      int km()
      {
          for(int i=1;i<=nn;i++)
              wx[i]=-inf,bel[i]=-1,wy[i]=0;
               
          for(int i=1;i<=nn;i++)
          {
              for(int j=1;j<=nn;j++)
              {
                  wx[i]=max(wx[i],weight[i][j]);
              }
          }
           
          for(int i=1;i<=nn;i++)
          {
              for(int j=1;j<=nn;j++)
              {
                  st[j]=inf;
              }
              while(1)
              {
                  for(int j=1;j<=nn;j++)
                      visx[j]=visy[j]=0;
                  if(dfs(i)) break;
                  int ret=inf;
                   
                  for(int j=1;j<=nn;j++)
                      if(!visy[j]&&ret>st[j])
                          ret=st[j];
                           
                  for(int j=1;j<=nn;j++)
                      if(visx[j])
                          wx[j]-=ret;
                  for(int j=1;j<=nn;j++)
                  {
                      if(visy[j])
                          wy[j]+=ret;
                      else
                          st[j]-=ret;
                  }
              }
          }
          int ans=0;
          for(int i=1;i<=nn;i++)
              if(~bel[i])
                  ans+=weight[bel[i]][i];
          return ans;
      }
      int solve()
      {
      	for(int i=1;i<=nn;i++)
          {
              for(int j=1;j<=nn;j++)
              {
                  weight[i][j]=-inf;
              }
          }
          getweight();
          return km();
      }
      
    3. 两个模板如果多次使用都要注意清空!

    4. 二分图有最优匹配首先得有最大匹配。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值