二分图的最大匹配——最大流EK算法

序:
既然是个图,并且求边数的最大值。那么这就可以转化为网络流的求最大流问题
只需要将源点与其中一子集的所有节点相连汇点与另一子集的所有节点相连,将所有弧的流量限制置为1,那么最大流 == 最大匹配。(感谢yulemao大神的指点)

只需要在初始化的时候修改一下,就可以直接用求最大流的算法模板了。
本文代码使用EK算法, 为POJ 1469的AC代码。
EK算法解析


源代码:

/*
About: 二分图最大匹配_网络流EK算法 
2017/04/22
*/
#include 
#include 
#include 
#include 
#include 
#include  
using namespace std;
#define INF 0x3f3f3f
#define maxm 200005
#define maxn 10005

struct Edge{
    int st, en, num;
    Edge(){}
    Edge(int s, int e, int n):
        st(s), en(e), num(n){}
}flow[maxm];

int n, m;
int st = maxn-2, en = maxn-1;
int pre[maxn], re[maxn][maxn/10], num[maxn];
int q[maxn], curr_pos, st_pos, end_pos, ne, max_flow;
bool wh[maxn];
int cur;

int input;

char *X, *Buffer, c;

void Get_All()
{
    long long file_lenth;
    fseek(stdin, 0, SEEK_END);
    file_lenth = ftell(stdin);
    rewind(stdin);
    Buffer = (char*)malloc(1*file_lenth);
    fread(Buffer,1, file_lenth, stdin);
    X = Buffer;
    return ;
}

int Get_Int()
{
    c = *X;
    input = 0;
    while(c < '0' || c > '9')   c = *++X;
    while(c >= '0' && c <= '9')
    {
        input = input*10+c-'0';
        c = *++X;
    }
    return input;
}

void Add_Edge(int st, int en)
{
    flow[cur] = Edge(st, en, 1);
    flow[cur^1] = Edge(en, st, 0);
    re[flow[cur].st][++num[flow[cur].st]] = cur;
    re[flow[cur].en][++num[flow[cur].en]] = cur^1;
    cur += 2;
    return ;
} 

void Init()
{
    cur = 0;
    memset(num, -1, sizeof num);
    max_flow = 0;
}

static void Read()
{
    int a, nums;
    n = Get_Int(), m = Get_Int();
    for(unsigned i = 0; i != n; ++i)
    {
        Add_Edge(st, i);
        nums = Get_Int();
        for(unsigned j = 0; j != nums; ++j)
        {
            a = Get_Int();
            Add_Edge(i, a+n);
        }
    }
    for(unsigned j = 1; j != m+1; ++j)
    {
        Add_Edge(j+n, en);
    }
    return ;
}

static bool Bfs(int st, int en)
{
    int i, j;
    st_pos = -1, end_pos = 0;
    memset(wh, 0, sizeof wh);
    wh[st] = 1;
    q[0] = st;
    while(st_pos != end_pos)
    {
        curr_pos = q[++st_pos];
        for(i = 0; i < num[curr_pos]+1; ++i)
        {
            j = re[curr_pos][i];
            if(flow[j].st == curr_pos && flow[j].num > 0 && !wh[flow[j].en])
            {
                ne = flow[j].en;
                wh[ne] = 1;
                pre[ne] = j;
                q[++end_pos] = flow[j].en;
                if(ne == en)    return true;         
            }
        }
    }
    return false;
} 

void EK(int start_pos, int end_pos)
{
    int i, minn;
    while(Bfs(start_pos, end_pos))
    {
        minn = INF;

        for(i = end_pos; i != st; i = flow[pre[i]].st)
        {
            minn = min(minn, flow[pre[i]].num);
        } 

        for(i = end_pos; i != st; i = flow[pre[i]].st)
        {
            flow[pre[i]].num -= minn;
            flow[pre[i]^1].num += minn;
        } 
        max_flow += minn;
    }
    return ;
}

void Print()
{
    if(max_flow == n)
    {
        cout << "YES" << endl; 
    }
    else
    {
        cout << "NO" << endl;
    }
    return ;
}

int main()
{
    freopen("test.in", "r", stdin);

    Get_All();
    int times = Get_Int();
    while(times --> 0)
    {
        Init();
        Read();
        EK(st, en);
        Print();
    }

    fclose(stdin);
    return 0;
}

需要注意的是,在实测中,上一篇文章所使用的匈牙利算法耗时70+ms,但是本文代码耗时600+ms
所以利用最大流算法计算二分图的最大匹配只是借鉴思路若不是有特殊原因,建议不使用


至此结束。
箜瑟_qi 2017.04.22 16:02

 

转载于:https://www.cnblogs.com/kongse-qi/p/6798871.html

你可能感兴趣的:(二分图的最大匹配——最大流EK算法)