二分图

一些概念

二分图的概念:

一个图G< V,E >,V可以划分成V1,V2,使得对于任意的一条边,这条边的两个端点分别在这两个子集当中,则称这样的图是二分图。

二分图的匹配:

对于一个二分图G< V1,V2,E >, 如果M是E的子集,并且M中的所有的边不存在公共的顶点,则称M是这个二分图的一个匹配。

完美匹配和极大匹配:

如果存在这样一个匹配覆盖了二分图中所有的点,则称这样的匹配是完美的匹配,如果一个匹配不能够通过增加边来使其增大,那么我们称这个匹配是极大匹配。

最大匹配:

所有的匹配中最大的匹配。

交错路径:

如果一条路径中的边交替的出现和不出现在一个匹配M中,那么我们则称这条路径是这个匹配的交错路径。

一些定理

引理1:

图G(V,E)中的任意两个匹配M,M’,的对称差,其分量要么是一条路径,要么是一个偶环
证明: 由于M,M’都是匹配,所以一个点v至多只和M或者M’中的一条边相匹配。所以如果是环的话,环上的边会交替的出现在M和M’当中,一定会是偶数环。

Berge定理:

M是图G(V,E)的一个最大匹配当且仅当不存在M的增广路径。
证明:
必要性:若M存在增广路径H,则H-M就是一个更大的匹配

充分性:反证法,我们假设存在一个更大的匹配M’,则会有|M’|>|M|, 则M和M’的对称差中,会由若干的偶环和路径组成。而在偶数环当中两个匹配中的边数相等。所以有一个分量中M’的边数大于M,这会是M的一条增广路径。

Berge定理为我们提供了一个寻找最大匹配的方法:不断寻找一个匹配的增广路径,直到无法继续扩张时,我们找到的匹配一定是最大的匹配。

Hall定理:

在二分图G(X,Y,E)中,对于任意X的子集X,都有|N(S)|>=S,则存在一个匹配M,使得所有的点都能够被匹配。
说明:对于一个X的子集S来说,其旁集N(S)中的点一定会在Y当中。所以,根据容斥原理,我们十分容易可以得到这个定理的正确性。

最大匹配算法

1.Hungary算法

基于Berg定理和Hall算法,尽力的寻找增广路径,找到了就将最大的匹配加1.
算法的时间复杂度O(m*n).

2. Hopcroft-Karp算法

在找到一个匹配之后,从S中一个未被匹配的点出发,寻找V中令一个未被匹配的点。如果找到,则就是找到一个部分匹配的增广路径。
再采用DFS增广原来的匹配。

/* 
 G = U ∪ V ∪ {NIL}
 where U and V are partition of graph and NIL is a special null vertex
*/

function BFS ()
    for u in U
        if Pair_U[u] == NIL
            Dist[u] = 0
            Enqueue(Q,u)
        else
            Dist[u] = ∞
    Dist[NIL] = ∞
    while Empty(Q) == false
        u = Dequeue(Q)
        if Dist[u] < Dist[NIL] 
            for each v in Adj[u]
                if Dist[ Pair_V[v] ] == ∞
                    Dist[ Pair_V[v] ] = Dist[u] + 1
                    Enqueue(Q,Pair_V[v])
    return Dist[NIL] != ∞

function DFS (u)
    if u != NIL
        for each v in Adj[u]
            if Dist[ Pair_V[v] ] == Dist[u] + 1
                if DFS(Pair_V[v]) == true
                    Pair_V[v] = u
                    Pair_U[u] = v
                    return true
        Dist[u] = ∞
        return false
    return true

function Hopcroft-Karp
    for each u in U
        Pair_U[u] = NIL
    for each v in V
        Pair_V[v] = NIL
    matching = 0
    while BFS() == true
        for each u in U
            if Pair_U[u] == NIL
                if DFS(u) == true
                    matching = matching + 1
    return matching

二分图的最佳匹配

我们可以将每一个二分图看成一个完备的二分图。(不存在的边权值为0),查找一个完美的匹配就是要去寻找一个最大匹配而且使其的权值最大。

KM算法:

这样的最佳匹配问题可以将其看作一个矩阵的截断问题。也就是说,从一个n*n的矩阵中选择n个数,而且这n个数不同行也不同列。
1.开始时,只有X存在顶标,顶标的大小是从X出发的边的最小的权值。
2.使用匈牙利算法查找增广路,如果找到,说明存在匹配。
3.若未找到增广路,则需要进行松弛操作,寻找最小的松弛数,所有的x标号高度降低d,所有的y标号增大d,然后再重新进行增广。
我们使用一个矩阵来看看发生了什么事情:
一开始时,矩阵的每一行减去其中最小的元素。

使用最少的边覆盖此时矩阵中出现的所有的0,如果我们覆盖成功了,那么说明我们成功找到了一个最佳的匹配。

若未成功,从矩阵中找到最小的一个元素,将除0以外矩阵中所有的元素都减去这个元素,然后再次尝试覆盖。

多次进行这样的操作,直到找到我们所需要的最佳匹配为止。

实际上,这是一个典型的贪心算法。

一道小题

< POJ1325 >As we all know, machine scheduling is a very classical problem in computer science and has been studied for a very long history. Scheduling problems differ widely in the nature of the constraints that must be satisfied and the type of schedule desired. Here we consider a 2-machine scheduling problem.
There are two machines A and B. Machine A has n kinds of working modes, which is called mode_0, mode_1, …, mode_n-1, likewise machine B has m kinds of working modes, mode_0, mode_1, … , mode_m-1. At the beginning they are both work at mode_0.
For k jobs given, each of them can be processed in either one of the two machines in particular mode. For example, job 0 can either be processed in machine A at mode_3 or in machine B at mode_4, job 1 can either be processed in machine A at mode_2 or in machine B at mode_4, and so on. Thus, for job i, the constraint can be represent as a triple (i, x, y), which means it can be processed either in machine A at mode_x, or in machine B at mode_y.
Obviously, to accomplish all the jobs, we need to change the machine’s working mode from time to time, but unfortunately, the machine’s working mode can only be changed by restarting it manually. By changing the sequence of the jobs and assigning each job to a suitable machine, please write a program to minimize the times of restarting machines.

算法的思路:
本题我们看到,一道作业可以在机器A的N状态下进行,也可以在机器B的M状态下进行。我们可以据此建立一个二分图。二分图中集合X的结点代表机器A的一个状态。集合Y的结点代表机器B的一个状态。那么如果有作业的进行需要M,N状态,则在两个结点之间连上一条边。则我们需要每一条边的两个顶点之一被选中。这就构成了最小顶点覆盖的问题。
可以证明最小顶点覆盖和二分图的最大匹配是相对应的。所以在建图之后才用匈牙利算法求最大匹配就可以解决这个问题。
注意到,如果一个作业可以在两个机器之一的0状态下进行,则不参加建图,因为机器的初始状态就是位于0状态。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define MAXN 205

int m,n,k;
int grid[MAXN][MAXN],match[MAXN],ans;
bool visited[MAXN];

void get_Graph()
{
    int i,x,y,j;
    memset(match,-1,sizeof(match));
    memset(grid,0,sizeof(grid));

    for(j=0;j<k;j++){
        scanf("%d%d%d",&i,&x,&y);
        if(!x || !y)continue;
        grid[x][y] = 1;
    }
}

bool Dfs(int cur)
{
    int i;
    for(i=0;i<m;i++){
        if(grid[cur][i] == 0 || visited[i])continue;
        else if(grid[cur][i] || !visited[i]){
            visited[i] = true;
            if(match[i] == -1|| Dfs(match[i])){
                match[i] = cur;
                return true;
            }
        }
    }
    return false;
}

void Solve()
{
    int i,j;
    ans = 0;
    for(i=0;i<n;i++){
        memset(visited,false,sizeof(visited));
        if(Dfs(i))ans++;
    }
    printf("%d\n",ans);
}

int main()
{
    freopen("input","r",stdin);
    while(scanf("%d",&n)!=EOF){
        if(!n)break;
        scanf("%d %d",&m,&k);
        get_Graph();
        Solve();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值