二分图的最佳完美匹配(和一些变形…

本文详细介绍了如何通过KM算法求解权值最大和最小的二分图完美匹配问题,包括匈牙利算法的原理、代码实现及特殊情况处理。通过不断寻找增广路径和更新可行顶标,确保找到最佳完美匹配。
摘要由CSDN通过智能技术生成
最佳完美匹配分两种:权值和最大的完美匹配、权值和最小的完美匹配。
时间复杂度都为:O(n^4) ;
1、权值和最大的完美匹配
用的算法是KM(匈牙利算法)。
下面分析一个这个算法的原理:
1、首先为每个点建立一个函数(可行顶标) , 使得对于任意的弧有l(x)+l(y)>=w[x][y] (弧有x、y组成 , w[x][y]是该弧的权值) , 假设这样的弧组成的图成为相等子图也就是原图的生成子图 , 如果这个相等子图存在最佳完美匹配 , 那么这个最佳完美匹配也就是原图的最佳完美匹配。
所以我们要做得就是寻找每个节点的函数(可行顶标)来建成存在最佳完美匹配的相等子图 。

2、构造可行顶标的思路:任意构造一个可行顶标(必须满足l(x)+l(y)>=w[x][y]) , 比如y结点顶标为0 , 而x结点的顶标为它出发所有边的最大权值

3、构成之后 , 再来求相等子图的最佳完美匹配 , 如果不存在 , 那么就改变可形顶标 , 来使更多的边进入相等子图 。

下面是代码:

#include
#include
#include
#include
#include
#include
using namespace std;

const int MAXN = 1000;
int w[MAXN][MAXN] , n , m; //  记录每条边的权值
int lx[MAXN] , ly[MAXN]; //  记录每个点的顶标
int pre[MAXN] ;  // 记录和y中点匹配的点是哪个点
bool s[MAXN] , t[MAXN] ; //  标记x和y的点是否被访问过

void init()
{
      memset(w , 0 , sizeof(w));
}

bool match(int i)  //  寻找增广路
{
      s[i] = true;
      for(int j = 1; j <= n; j++)
            if(lx[i]+lx[j] == w[i][j] && !t[j])
            {
                  t[j] = true;
                  if(!pre[j] || match(pre[j]))
                  {
                        pre[j] = i;
                        return true;
                  }
            }
      return false;
}

void update()
{
      int a = 1<<30 , i;
      for(i = 1; i <= n; i++) 
            if(s[i])  //  如果x中的这个点已被标记
                  for(int j = 1; j <= n; j++)
                        if(!t[i]) //  如果这个点在y中没有被标记 , 和前面的判断 , 就可以寻找到飞匹配点。
                              a = min(a , lx[i]+ly[j]-w[i][j]);  //  找到最小的a , 因为这样才能保证是最佳完美匹配
      for(i = 1; i <= n; i++)
      {
            if(s[i])  lx[i] -= a;  //  只有被标记的点 , 才修改其顶标
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值