精华内容
下载资源
问答
  • 基于二分图的常用算法 最大匹配——匈牙利算法 最佳匹配——KM算法 感谢原作者
  • 数学建模常用经典算法集合均已成功编译-二分图最大匹配算法BGMMA.rar 数学建模常用经典算法集合(均已成功编译) 扰!
  • 最佳二分图匹配算法(总结)

    千次阅读 2018-07-20 16:35:13
    通过调整加权完全二分图的可行顶标,将加权完全二分图转化为无权二分图,使得加权完全二分图的最佳匹配与转化后的无权二分图的最佳匹配相同,在此基础上采用匈牙利算法。 最小费用最大流算法 O(n*e) 将带权二分图...

    EK算法     O(n*e^2)

    通过调整加权完全二分图的可行顶标,将加权完全二分图转化为无权二分图,使得加权完全二分图的最佳匹配与转化后的无权二分图的最佳匹配相同,在此基础上采用匈牙利算法。

    最小费用最大流算法    O(n*e)

    将带权二分图转化为相应的网络流图,

    1)构建源点s跟汇点t

    2)对于i\inX,建立一条容量为1,费用为0的有向边(s,i).

    3)对于j\inY,建立一条容量为1,费用为0的有向边(j,t).

    4)对于E中的每一条边(i,j)(i\inX,j\inY),建立一条容量为1,费用为该边所对应权值的有向边(i,j)。

    容易看出,网络流D的最小费用最大流,恰好使X,Y中的节点两两配对起来,对应着二分图的最佳匹配。

    展开全文
  • 二分图最大匹配算法

    2015-01-28 14:54:43
    二分图指的是这样一种图,其所有顶点可以分成两个集合X和Y,...给定一个二分图G,M为G边集的一个子集,如果M满足当中的任意两条边都不依附于同一个顶点,则称M是一个匹配。图中包含边数最多的匹配称为图的最大匹配
  • 二分图匹配算法模板

    2021-04-13 11:52:49
    二分图匹配算法模板 #include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 505; int mat[N][N]; // boy[i] = j 选中i号男生的女生编号 int boy[N]; ...

    二分图匹配算法模板

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    const int N = 505;
    int mat[N][N];
    // boy[i] = j 选中i号男生的女生编号
    int boy[N];
    int vis[N];
    //k边数 n男生个数 m女生个数
    int k,m,n;
    //传入女生编号
    bool dfs(int x)
    {
    	for (int i = 0; i <= n; ++i)
    	{
    		if (mat[x][i] == 1 && !vis[i])
    		{
    			vis[i] = 1;
    			//下面一行代码是二分图匹配的精髓
    			if(boy[i] == 0 || dfs(boy[i]))
    			{
    				boy[i] = x;
    				return true;
    			}
    		}
    	}
    	return false;
    }
    int main()
    {
    	scanf("%d%d", &m, &n);
    	memset(mat, 0, sizeof(mat));
    	memset(boy, 0, sizeof(boy)); 
    	for(int i = 1; i <= k; i++){
    		int x, y;
    		scanf("%d%d", &x, &y);
    		mat[x][y] = 1;
    	}
    	int ans = 0;
    	for(int i = 1;i < m;i++)
    	{
    		 memset(vis, 0, sizeof(vis));
    		 if(dfs(i)) ans++;
    	}
    	printf("%d\n", ans);
    }
    

    每个顶点 Vi 只能选择一次,因此算法的整体时间复杂度是 O(V*E)

    展开全文
  • 什么是二分图匹配问题?       二分即将图中的顶点分为两类,一类顶点中可以匹配另一类顶点,组成一组带权的关系,求如何匹配总权值最大。 通过一个例题来看一下: 运动员最佳配...

    什么是二分图的匹配问题?

          二分即将图中的顶点分为两类,一类顶点中可以匹配另一类顶点,组成一组带权的关系,求如何匹配总权值最大。

    通过一个例题来看一下:

    运动员最佳配问题。羽毛球队有男女运动员各n人。给定两个nXn矩阵P和Q。P[i][i]是男运动员i和
    女运动员j配对组成混合双打的竞赛优势;Q[i][j]是女运动员i和男运动员j配合的竞赛优势。由于技术
    配合和心理状态等各种因素影响,P[i][j]不一定等于Q[j][i]。设计一个算法,计算男女运动员最佳配
    对法,使各组男女双方竞赛优势乘积的总和达到最大。
    

    这个问题就是一个标准的二分图的匹配问题,解决这类问题有两种方法

    暴力搜索

    顺着思路去想,肯定想到的首先是暴力搜索,这个问题可以转换为全排列去做,把男生固定为层数,第一层就是第一个男生可以选取的女生,第二层就是第二个男生在第一个男生选择完的基础上继续可以选择的个数。

    在这里插入图片描述
    所以,每到叶子节点就可以得到一个组合,遍历整棵树就可以得到所有的组合,所以遍历整棵树使用DFS+回溯的思想去解决这个问题

    /**
     *  暴力搜索树P(DFS+回溯),然后在Q中找出对应的值,计算总和
     */
    public class Main_1 {
        /**
         * P二维矩阵存储p矩阵
         * Q二维矩阵存储q矩阵
         */
        static int[][] P = {{10,2,3},
                {2,3,4,},
                {3,4,5}};
        static int[][] Q = {{2,2,2},
                {3,5,3},
                {4,5,1}};
        /**
         * stack 保存回溯中男运动员选取女运动员的数组中标号
         */
        static Stack<Integer> stack;
        /**
         * sum 保存最大权值
         */
        static int sum;
        public static void main(String[] args) {
            /**
             * 初始化子数组
             */
            int[] array = new int[P.length];
            for (int i = 0; i < array.length; i++) {
                array[i] = i;
            }
            /**
             * 初始化栈
             */
            stack = new Stack<>();
            /**
             * 递归回溯
             */
            search(array);
        }
    
        /**
         * 递归回溯
         * @param array 子数组
         */
        public static void search(int[] array) {
            /**
             * 当数组的长度小于0时,退出递归
             */
            if(array.length<=0){
                /**
                 * temp 当前组合的总权值
                 * 并且输出当前的组合
                 */
                int temp = 0;
                for (int i = 0; i < stack.size(); i++) {
                    temp += P[i][stack.get(i)]*Q[stack.get(i)][i];
                    //System.out.print(stack.get(i) + " ");
                    System.out.print(i+" ");
                    System.out.print(stack.get(i)+"  ");
                }
                /**
                 * 但当前组合计算的总权值大于保存的最大权值就直接覆盖
                 */
                if(temp > sum) {
                    sum = temp;
                }
                System.out.println(temp);
                return;
            }
            int[] subArray = new int[array.length-1];
            /**
             * 每次递归将数组中未选取的内容分割出来成为一个新的数组
             * 然后就本次递归的值入栈
             * 递归结束的时候将入栈的值出栈
             * 利用栈实现回溯
             */
            for (int i = 0; i < array.length; i++) {
                System.arraycopy(array,0,subArray,0,i);
                System.arraycopy(array,i+1,subArray,i,array.length-i-1);
                stack.push(array[i]);
                search(subArray);
                stack.pop();
            }
        }
    }
    
    

    解释:

    P代表题目描述的P数组
    Q代表题目描述的Q数组
    Stack表示一个栈,在回溯时会用到。
    Sum 用来记录最大的权值
    Main()主函数
    Search()函数 递归遍历树
    

    遍历整棵树也就是要访问到树的每一个节点,所以很明显时间复杂度为O(n!),一旦顶点数过多,这种方法是不可行的。

    KM算法

    KM算法是二分图的最优权值问题的解决方案,通过定点的权值不断的变化,从而推出最优权值的组合,KM算法的模板完美的解决这个问题。

    图的存储使用邻接矩阵的方式

    public class KM {
        int[][] graph;        //假设graph的行是顶点X集合(其中的顶点简称X顶点),列是顶点Y集合(其中的顶点简称Y顶点)
        boolean[] xUsed;      //在每次循环中每个X顶点是否访问过
        boolean[] yUsed;      //在每次循环中每个Y顶点是否访问过
        int[] match;          //每个Y顶点匹配的X顶点,即第i个Y顶点匹配的是第match[i]个X顶点
        int len;              //图的大小为len*len
        int[] less;           //保存左边节点与右边节点相加与权值的差值
        private static final int INFINITE = 0x6fffffff;
    
        int[] X; //每个X顶点的顶标
        int[] Y; //每个Y顶点的顶标,初始化为0
    
        /**
         * 初始化函数
         * @param data 传入x顶点和y顶点的领接矩阵
         */
        public KM(int[][] data) {
            this.graph = data;
            len = data.length;
            xUsed = new boolean[len];
            yUsed = new boolean[len];
            match = new int[len];
            less = new int[len];
    
            X = new int[len];
            Y = new int[len];
    
            for (int i = 0; i < len; i++) {
                match[i] = -1;
            }
    
            //初始化每个X顶点的顶标为与之相连的边中最大的权
            for (int k = 0; k < len; k++) {
                X[k] = data[k][0];
                for (int l = 0; l < len; l++) {
                    X[k] = X[k] >= data[k][l] ? X[k] : data[k][l];
                }
            }
        }
    
        void km() {
            //遍历每个X顶点
            for (int i = 0; i < len; i++) {
                /**
                 * 给less数组赋值为最大值,less数组为了找到顶点值的相差值
                 */
                for (int j = 0; j < len; j++) {
                    less[j] = INFINITE;
                }
                /**
                 * 寻找能与X顶点匹配的Y顶点,如果找不到就降低X顶点的顶标继续寻找
                 */
                while (true) {   
                    for (int j = 0; j < len; j++) {
                        xUsed[j] = false;
                        yUsed[j] = false;
                    }
                    if (hungaryDFS(i)) break;  //寻找到匹配的Y顶点,退出
                    //如果没有找到能够匹配的Y顶点,则降低X顶点的顶标,提升Y顶点的顶标,再次循环
                    int diff = INFINITE;        //diff是顶标变化的数值
                    for (int j = 0; j < len; j++) {
                        if (!yUsed[j]) diff = diff <= less[j] ? diff : less[j];
                    }
                    //diff等于为了使该顶点X能够匹配到一个Y顶点,其X的顶标所需要降低的最小值
    
                    //更新顶标,左加右减
                    for (int j = 0; j < len; j++) {
                        if (xUsed[j]) X[j] -= diff;
                        if (yUsed[j]) Y[j] += diff;
                        else less[j] -= diff;
                    }
                }
            }
    
            //匹配完成,可以输出结果
            int res = 0;
            for (int i = 0; i < len; i++) {
                res += graph[match[i]][i];
            }
            System.out.println("最终最大权值:" + res);
        }
    
        private boolean hungaryDFS(int i) {
            //设置这个X顶点在此轮循环中被访问过
            xUsed[i] = true;
    
            //对于这个X顶点,遍历每个Y顶点
            for (int j = 0; j < len; j++) {
                if (yUsed[j]) continue;   //每轮循环中每个Y顶点只访问一次
                int gap = X[i] + Y[j] - graph[i][j];      //KM算法的顶标变化公式
    
                //只有X顶点的顶标加上Y顶点的顶标等于graph中它们之间的边的权时才能匹配成功
                if (gap == 0) {
                        yUsed[j] = true;
                        if (match[j] == -1 || hungaryDFS(match[j])) {
                            match[j] = i;
                            return true;
                        }
                } else {
                    less[j] = less[j] <= gap ? less[j] : gap;
                }
            }
    
            return false;
        }
    
        public static void main(String[] args) {
            int[][] graph = {
                    {20,4,6},
                    {6,15,12},
                    {12,20,5}
                    /*{3,0,4},
                    {2,1,3},
                    {0,0,5}*/
            };
            new KM(graph).km();
        }
    }
    
    
    展开全文
  • 我的前一篇文章介绍了对于分配问题的Kuhn-Munkre算法,该算法其实可以看作是邻接矩阵形式的匈牙利算法,如果更抽象地看这个算法,它可以看成是一个二分图匹配算法的变体算法,具体的说,是二分图最大权重匹配算法。...

    我的前一篇文章介绍了对于分配问题的Kuhn-Munkre算法,该算法其实可以看作是邻接矩阵形式的匈牙利算法,如果更抽象地看这个算法,它可以看成是一个二分图匹配算法的变体算法,具体的说,是二分图最大权重匹配算法。我打算也把二分图最大权重匹配算法也介绍下,不过最大权重匹配算法又是基于最大匹配算法设计的,所以这篇文章先介绍二分图的最大匹配算法

    二分图最大匹配问题

    分配问题从图论的角度看其实是一个二分图(Bipartite Graph),就是说图中有两个点集,在各自的点集内的点互相没有连接,两个点集间的点可以连接,每个点存在多个允许的连接,如下图所示:
    在这里插入图片描述

    如果我们对二分图中的每个点,都确定最多只有一条连接,那么称之为该二分图的一个匹配,例如:
    在这里插入图片描述
    如果每个点都有一条线确定,即匹配的线数正好等于单个点集点数 n n n,那么称之为完美匹配,如下图:
    在这里插入图片描述
    对应于现实问题,我们当然希望尽量达到完美匹配,但是因为点的可选连线情况可能导致无论如何也达不到完美匹配,所以自然而然产生了最大匹配问题(Max-Bipartite Matching),最大可以找到多少条匹配线

    用数学语言描述:

    • G = ( V , E ) G=(V,E) G=(V,E)是一个二分图, n = ∣ V ∣ n=|V| n=V m = ∣ E ∣ m=|E| m=E δ ( v ) , v ∈ V \delta(v), v\in V δ(v),vV表示一端连接到点 v v v的所有边, x e ∈ { 0 , 1 } x_e\in \{0,1\} xe{0,1}表示边 e e e是否被选中,则有最大匹配问题:
      m a x ∑ e ∈ E x e s . t . ∑ e ∈ δ ( v ) ≤ 1 , ∀ v ∈ V x e ∈ { 0 , 1 } , ∀ e ∈ E \begin{aligned} max\quad& \sum_{e\in E} x_e\\ s.t.\quad& \sum_{e\in \delta(v)}\leq 1,\forall v \in V \\ & x_e\in \{0,1\},\forall e \in E \\ \end{aligned} maxs.t.eExeeδ(v)1,vVxe{0,1},eE

    算法主流程

    在介绍算法前,先定义一些专用的算法术语,这些术语是算法的必备要素

    • 自由顶点(free vertex):就是指当前匹配结果下没有任何连线的点
    • 交替路径(alternating path): 由匹配边和非匹配边交替构成的一条路径,例如下面的图,加重的边表示已经在当前匹配中确定的边,细线表示还没确定的边
      在这里插入图片描述
    • 增广路径(augmenting path):属于交替路径,不过它的首末顶点都是自由顶点,即开头和最后的两条边必须是非匹配边,如下图所示
      在这里插入图片描述

    我们观察一下增广路径,它是一条匹配边接一条非匹配的构造,并且首末两条边都是未确定的,如果我们把这个路径"翻转"一下,把匹配边变成非匹配,非匹配变为匹配,那么可以发现,这条路径上的匹配数会多出1:
    在这里插入图片描述
    这就给了我们启发,只要我们能在当前匹配的二分图中找到一条增广路径,那么就能扩充1数量的匹配;从数学理论上看也确实如此,最大匹配算法的理论前提就是:

    • 对于一个二分图,一个匹配 M M M是最大的,当且仅当图 G G G M M M的基础上找不到任何增广路径

    自然地,我们就得到了算法的主流程:

    1. 初始化匹配 M M M M = ∅ M=\empty M=
    2. 在当前匹配的基础上,在图 G G G中搜索增广路径 P P P
    3. 如果存在 P P P,对增广路径进行翻转更新匹配 M M M,回到步骤2
    4. 输出 M M M

    搜索增广路径

    但是怎么搜索增广路径还是需要一个专门的子算法来处理;搜索过程一定是从一个自由顶点开始,到一个自由顶点结束,并且匹配边与非匹配边交替进行;这里介绍一种把匹配图转化成有向图的深度优先路径搜索算法:新增一个首节点 s s s和一个末结点 t t t,对于当前二分图中未确定的边,我们将其方向置为 X X X Y Y Y,对于匹配边,将方向置为 Y Y Y X X X;对于 X X X中未匹配的点,我们添加从 s s s到该点的边;对于 Y Y Y中未匹配的点,我们添加从该点到 t t t的边;这样二分图变成了一个有向图,我们采用深度优先遍历搜索从 s s s t t t的最短路径,如果能搜索到一条路径,那么去掉首末结点后就是一条增广路径

    举个例子,当前二分图的匹配如下图所示:
    在这里插入图片描述
    将其转化成一个有向图:
    在这里插入图片描述
    然后我们就可以搜索到一条最短路径 s → x 0 → y 0 → x 1 → y 1 → t s\rightarrow x_0 \rightarrow y_0 \rightarrow x_1 \rightarrow y_1 \rightarrow t sx0y0x1y1t,去掉 s s s t t t,就是一条增广路径

    代码实现

    我写了一段python代码来实现上述的算法过程。定义了MaxMatchAlgorithm类,它只需要一个边矩阵作为输入,矩阵的行列分别表示二分图的 X X X Y Y Y,矩阵的每个元素表示该边是否可选;maxMatch实现了算法的主流程,getAugmentingPath方法用于搜索增广路径,invert方法则用于翻转增广路径

    import numpy as np
    
    class MaxMatchAlgorithm:
        def __init__(self, edges):
            '''
            edges : Matrix with num_x X num_y size
            '''
            self.num_x=edges.shape[0]
            self.num_y=edges.shape[1]
            self.edges=edges
    
        def maxMatch(self):
            matches=[]
            iter=1
            while True:
                print("######## iteration "+str(iter)+" ##############")
                print("...")
                print("...")
                iter+=1
                augPath=self.getAugmentingPath(matches)
                if len(augPath)==0:
                    break
                matches=self.invert(augPath,matches) 
            return matches
        
        def invert(self, augPath, matches):
            for i in range(len(augPath)):
                if i%2==0:
                    if augPath[i][2]:
                        matches.append((augPath[i][0],augPath[i][1]))
                    else:
                        matches.append((augPath[i][1],augPath[i][0]))
                else:
                    removeIndex=-1
                    for index in range(len(matches)):
                        if (matches[index][0]==augPath[i][0] and matches[index][1]==augPath[i][1]) or (matches[index][0]==augPath[i][1] and matches[index][1]==augPath[i][0]):
                            removeIndex=index
                            break
                    matches.pop(removeIndex)
            return matches
    
        def getAugmentingPath(self,matches):
            #directMatrix[i,j]=1 : x_i -> y_j
            totalVertexN=self.num_x+self.num_y+2
            directMatrix=np.zeros((totalVertexN,totalVertexN))
            for i in range(0,totalVertexN-1):
                for j in range(0,totalVertexN):
                    if i==0 and j>=1 and j<=self.num_x:
                        directMatrix[i,j]=1
                        continue
                    if j==totalVertexN-1 and i>self.num_x:
                        directMatrix[i,j]=1
                        continue
                    if i==j or i==0 or j==0 or j==totalVertexN-1:
                        continue
                    iIsX=False
                    jIsX=False
                    if i>0 and i<=self.num_x:
                        iIsX=True
                    elif i>self.num_x and i<=totalVertexN-2:
                        iIsX=False
                    if j>0 and j<=self.num_x:
                        jIsX=True
                    elif j>self.num_x and j<=totalVertexN-2:
                        jIsX=False
                    if iIsX and jIsX==False:
                        directMatrix[i,j]=self.edges[i-1,j-1-self.num_x]
            for (x,y) in matches:
                directMatrix[x+1,y+1+self.num_x]=0
                directMatrix[y+1+self.num_x,x+1]=1
            
            for j in range(1, self.num_x+1):
                isMatched=False
                for k in range(self.num_x, totalVertexN-1):
                    if directMatrix[k][j]==1:
                        isMatched=True
                        break
                if isMatched:
                    directMatrix[0][j]=0
            
            for i in range(self.num_x, totalVertexN-1):
                isMatched=False
                for k in range(1, self.num_x+1):
                    if directMatrix[i][k]==1:
                        isMatched=True
                        break
                if isMatched:
                    directMatrix[i][totalVertexN-1]=0
    
            shortestRoute=self.findRoute(directMatrix,[0],[])
            augmentingPath=[]
            for i in range(1,len(shortestRoute)-2):
                vertexIndex_A=shortestRoute[i]
                actualIndex_A=0
                vertexIsX_A=False
                if vertexIndex_A>=1 and vertexIndex_A<=self.num_x:
                    actualIndex_A=vertexIndex_A-1
                    vertexIsX_A=True
                else:
                    actualIndex_A=vertexIndex_A-1-self.num_x
    
                vertexIndex_B=shortestRoute[i+1]
                actualIndex_B=0
                vertexIsX_B=False
                if vertexIndex_B>=1 and vertexIndex_B<=self.num_x:
                    actualIndex_B=vertexIndex_B-1
                    vertexIsX_B=True
                else:
                    actualIndex_B=vertexIndex_B-1-self.num_x
                
                augmentingPath.append((actualIndex_A,actualIndex_B,vertexIsX_A))
            
            return augmentingPath
    
        def findRoute(self, directMatrix, currentRoute, currentShortestRoute):
            if currentRoute[-1]==directMatrix.shape[0]-1:
                if len(currentShortestRoute)==0 or len(currentShortestRoute)>len(currentRoute):
                    currentShortestRoute=currentRoute.copy()
                return currentShortestRoute
            for i in range(0,directMatrix.shape[0]):
                if directMatrix[currentRoute[-1],i]==1:
                    nextRoute=currentRoute.copy()
                    nextRoute.append(i)
                    route=self.findRoute(directMatrix, nextRoute,currentShortestRoute)
                    if len(currentShortestRoute)==0 or len(currentShortestRoute)>len(route):
                        currentShortestRoute=route.copy()
            return currentShortestRoute
    

    用下面的代码测试,输入数据就是上面的例子:

    import numpy as np
    from MaxMatchAlgorithm import MaxMatchAlgorithm  
    
    edges=np.array([
        [1,0,1],
        [1,1,1],
        [0,0,1]
    ])
    
    maxMatchAlgorithm=MaxMatchAlgorithm(edges)
    print(maxMatchAlgorithm.maxMatch())
    

    结果
    在这里插入图片描述
    对应图上就是
    在这里插入图片描述

    展开全文
  • 匈牙利算法 二分图匹配 matlab代码 最近学习了一下匈牙利算法,写了个拙劣的代码,噗 希望可以和大噶交流~ 程序是基于增广路径方法的递归结构 算法流程图 代码 %% % % % % % % % % % % % % % % % % % % % % % % %...
  • 二分图匹配算法总结

    千次阅读 2013-03-09 17:29:54
    最近在学习二分图相关算法,以下内容是根据自己的理解,欢迎讨论。 什么是二分图:  二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中...
  • 算法讲解:二分图匹配【图论】

    万次阅读 多人点赞 2018-07-23 09:46:34
    二分图匹配,自然要先从定义入手,那么二分图是什么呢? 二分图: 二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所...
  • 这是做建模作业是用的的二分图匹配算法 原题如下 该代码测试数据如下 1 1 1 2 2 1 3 1 3 2 4 2 5 3 5 4 5 5 6 1 7 3 7 4 8 2 8 3 测试结果如图 #include <stdio.h> #include <stdlib.h> #include<...
  • 二分图匹配(一)

    2020-11-30 20:37:38
    文章目录什么是二分图:例题:NC111768 CF741C题目描述:题解:代码:二分图最大匹配匈牙利算法算法思想:代码:König定理二分图最优匹配KM(Kuhn-Munkres)算法算法思路:具体操作代码:复杂度 什么是二分图二分...
  • 先看看洛谷上面的二分图匹配有关匈牙利算法的题目。 题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式:   第一行,n,m,e 第二至e+1行,...
  • 利用c语言实现寻找二分图最大匹配算法。给定一个二分图二分图中的任一匹配,通过最大匹配算法,确定该匹配是否是最大匹配并输出最大匹配的边集。最大匹配:M是一个二分图边集的子集,当M中任意两个边在顶点处不...
  • 二分图匹配之HK算法(知识点总结)

    千次阅读 2019-07-19 21:56:59
    而HK算法每次处理所有长度为d的增广路,将其用一次O(m)的复杂度匹配完 板子整理(以poj1469为例) //hopcroft_karp算法,复杂度O(sqrt(n)*m) #include #include #include #include #include #include ...
  • 二分图的最大匹配算法

    万次阅读 2018-08-16 16:35:01
    二分图的概念:二分图是图中的一种特殊模型,如果图...本文通过一个问题来引出二分图的最大匹配算法 。以素数伴侣的题目为例:若两个正整数的和为素数,则这两个数称为素数伴侣,设计程序从已有的N个正整数中挑出若...
  • 二分图匹配算法总结转自http://old.blog.edu.cn/user3/Hailer/archives/2007/1829623.shtml二分图最大匹配的匈牙利算法 二分图是这样一个图,它的顶点可以分类两个集合X和Y,所有的边关联在两个顶点中,恰好一个...
  •  在正式的讲这个算法之前,不妨想一想,还有什么办法可以比较快速的计算出二分图的最大匹配?没错,网络的最大流算法可以搞定:我们需要增加额外的源汇点S,T,则对于图 1-1我们很容易得到如图1-2所示的网络模型,...
  • 二分图匹配算法

    2014-08-26 14:25:37
     二分图最大匹配的经典匈牙利算法是由Edmonds在1965年提出的,算法的核心就是根据一个初始匹配不停的找增广路,直到没有增广路为止。  匈牙利算法的本质实际上和基于增广路特性的最大流算法还是相似的,只需要注意...
  • 2、二分图匹配算法(匈牙利算法) 二分图匹配就是找到一个边的集合,是的图中每个顶点的度数为1; 比如目标是: 二分图的完美匹配:就是所有的顶点都有匹配点,这样的叫做完美匹配,上图中的所有点都有匹配点,所以...
  • 例如,有一组压缩气缸和一组压缩活塞,每一个型号的压缩气缸有一个固定的内径大小,每一个型号的压缩活塞可以匹配内径在一定范围内的气缸,使用匈牙利算法得到活塞和气缸对大匹配数的方案。 2、二分图定义 二分图...
  • 二分图匹配问题以及相关 算法模板 二分图的判定 染色法 染色法原理: 首先任意取出一个顶点进行染色,和该节点相邻的点有三种情况: 1.如果未染色,那么继续染色此节点(染为另一种颜色) 2.如果已染色但和当前...
  • 概述: 匈牙利算法是一种借助增广路来求二分图最大匹配问题的算法 增广路: 从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替路称为增广路 如上图所示,9-4-8-1-6-2就是一条...
  • 无权二分图匹配与匈牙利算法 二分图:简单来说就是图中的点可以分成两部分,并且每一部分里面都没有边相连,任意一条边起点和终点都不在同一个点集。 匹配:边的集合,任意两条边都没有公共点。 匹配点,匹配边...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,581
精华内容 6,632
关键字:

二分图匹配算法